ZQuest Classic Coverage Report


Directory: src/
File: src/gui/jwin.cpp
Date: 2024-08-29 07:59:21
Exec Total Coverage
Lines: 198 5632 3.5%
Functions: 16 148 10.8%
Branches: 251 4357 5.8%

Line Branch Exec Source
1 #include <ctype.h>
2 #include <cstring>
3 #include "base/zapp.h"
4 #include "base/zc_alleg.h"
5 #include <allegro/internal/aintern.h>
6 #include "gui/jwin.h"
7 #include "gui/editbox.h"
8 #include <iostream>
9 #include <sstream>
10 #include "base/zsys.h"
11 #include <stdio.h>
12 #include "base/util.h"
13 #include "pal.h"
14 #include "gui/tabpanel.h"
15 #include "gui/text_field.h"
16 #include "dialog/info.h"
17 #include "drawing.h"
18 using namespace util;
19 using std::string;
20 using std::istringstream;
21
22 void update_hw_screen();
23 extern int32_t zq_screen_w, zq_screen_h;
24 extern int32_t joystick_index;
25 int CheckerCol1 = 7, CheckerCol2 = 8;
26
27 extern bool is_editor();
28
29 int32_t abc_patternmatch = 1;
30
31 char abc_keypresses[1024] = {0};
32 void wipe_abc_keypresses() { memset(abc_keypresses, 0, 1024); }
33
34 /* these are provided for external use */
35 int32_t jwin_colors[jcMAX] =
36 {
37 0xC0C0C0,0xF0F0F0,0xD0D0D0,0x808080,0x404040,0x000000,
38 0x000080,0x00F0F0,0xFFFFFF,0xFFFFFF,0x000000,0x000080,0xFFFFFF
39 };
40
41 int32_t scheme[jcMAX] =
42 {
43 0xC0C0C0,0xF0F0F0,0xD0D0D0,0x808080,0x404040,0x000000,
44 0x000080,0x00F0F0,0xFFFFFF,0xFFFFFF,0x000000,0x000080,0xFFFFFF
45 };
46
47 int32_t jwin_pal[jcMAX] = {0};
48
49 // A pointer to this variable is used to identify the DIALOG belonging to
50 // the DialogRunner. It isn't used for anything else.
51 char newGuiMarker;
52
53 int32_t new_gui_event(DIALOG* d, guiEvent event)
54 {
55 for(int32_t i = 0; true; --d, ++i)
56 {
57 if(d->dp3 == &newGuiMarker)
58 {
59 d->d1 = i;
60 return d->proc(MSG_GUI_EVENT, d, event);
61 }
62 }
63
64 return -1;
65 }
66
67 void close_new_gui_dlg(DIALOG* d);
68
69 int32_t bound(int32_t x,int32_t low,int32_t high)
70 {
71 if(x<low) x=low;
72
73 if(x>high) x=high;
74
75 return x;
76 }
77 /*
78 float bound(float x,float low,float high)
79 {
80 if(x<low) x=low;
81 if(x>high) x=high;
82 return x;
83 }
84 */
85
86 int32_t get_selected_tab(TABPANEL* panel)
87 {
88 for(int32_t i=0; panel[i].text; ++i)
89 {
90 if((panel[i].flags&D_SELECTED)!=0)
91 return i;
92 }
93 return -1;
94 }
95
96 /* jwin_set_colors:
97 * Loads a set of colors in 0xRRGGBB or 256-color-indexed format
98 * into the current color scheme using the appropriate color depth
99 * conversions.
100 */
101 176 void jwin_set_colors(int32_t *colors)
102 {
103 176 int32_t i = 0;
104
105
1/2
✓ Branch 0 taken 176 times.
✗ Branch 1 not taken.
176 if(bitmap_color_depth(screen) == 8)
106 {
107 // use color indices
108
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 3696 times.
3872 for(; i<jcMAX; i++)
109 3696 scheme[i] = colors[i];
110 176 }
111 else
112 {
113 // 0xRRGGBB format
114 for(; i<jcMAX; i++)
115 scheme[i] = makecol(colors[i]>>16, (colors[i]>>8)&0xFF, colors[i]&0xFF);
116 }
117 176 }
118
119 /* jwin_set_dialog_color:
120 * Sets the foreground and background colors of all the objects in a dialog.
121 *
122 * Needs work!
123 */
124 void jwin_set_dialog_color(DIALOG *dialog)
125 {
126 int32_t c;
127
128 for(c=0; dialog[c].proc; c++)
129 {
130 dialog[c].fg = scheme[jcMEDDARK];
131 dialog[c].bg = scheme[jcBOX];
132 }
133 }
134
135 /* jwin_draw_frame:
136 * Draws a frame using the specified style.
137 */
138 void jwin_draw_frame(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t style)
139 {
140 optional<int> c1,c2,c3,c4;
141
142 switch(style)
143 {
144 case FR_INVIS:
145 return;
146 case FR_BOX:
147 c1 = jcLIGHT;
148 c2 = jcMEDLT;
149 c3 = jcMEDDARK;
150 c4 = jcDARK;
151 break;
152
153 case FR_INV:
154 c1 = jcDARK;
155 c2 = jcMEDDARK;
156 c3 = jcMEDLT;
157 c4 = jcLIGHT;
158 break;
159
160 case FR_DEEP:
161 c1 = jcMEDDARK;
162 c2 = jcDARK;
163 c3 = jcMEDLT;
164 c4 = jcLIGHT;
165 break;
166
167 case FR_DARK:
168 c1 = jcDARK;
169 c2 = jcMEDDARK;
170 c3 = jcMEDDARK;
171 c4 = jcDARK;
172 break;
173
174 case FR_ETCHED:
175 c1 = jcMEDDARK;
176 c2 = jcLIGHT;
177 c3 = jcMEDDARK;
178 c4 = jcLIGHT;
179 break;
180
181 case FR_MEDDARK:
182 c1 = jcMEDDARK;
183 c2 = jcBOX;
184 c3 = jcBOX;
185 c4 = jcMEDDARK;
186 break;
187
188 case FR_MENU:
189 c1 = jcLIGHT;
190 c4 = jcMEDDARK;
191 break;
192 case FR_MENU_INV:
193 c1 = jcMEDDARK;
194 c2 = jcMEDDARK;
195 c3 = jcLIGHT;
196 c4 = jcLIGHT;
197 break;
198
199 case FR_WIN:
200 default:
201 c1 = jcMEDLT;
202 c2 = jcLIGHT;
203 c3 = jcMEDDARK;
204 c4 = jcDARK;
205 break;
206 }
207
208 if(c1) c1 = scheme[*c1];
209 if(c2) c2 = scheme[*c2];
210 if(c3) c3 = scheme[*c3];
211 if(c4) c4 = scheme[*c4];
212 switch (style)
213 {
214 case FR_RED:
215 c1 = 0xE4;
216 c2 = 0xEC;
217 c3 = 0xE4;
218 c4 = 0xEC;
219 break;
220 case FR_GREEN:
221 c1 = 0xE2;
222 c2 = 0xEA;
223 c3 = 0xE2;
224 c4 = 0xEA;
225 break;
226 }
227 if(c1)
228 {
229 hline(dest, vbound(x,0,dest->w-1), vbound(y,0,dest->h-1) , vbound(x+w-2, 0,dest->w-1), *c1);
230 vline(dest, vbound(x,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(y+h-2, 0, dest->h-1), *c1);
231 }
232 if(c2)
233 {
234 hline(dest, vbound(x+1,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(x+w-3,0,dest->w-1), *c2);
235 vline(dest, vbound(x+1,0,dest->w-1), vbound(y+2,0,dest->h-1), vbound(y+h-3,0,dest->h-1), *c2);
236 }
237 if(c3)
238 {
239 hline(dest, vbound(x+1,0,dest->w-1), vbound(y+h-2,0,dest->h-1), vbound(x+w-2,0,dest->w-1), *c3);
240 vline(dest, vbound(x+w-2,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(y+h-3,0,dest->h-1), *c3);
241 }
242 if(c4)
243 {
244
245 hline(dest, vbound(x,0,dest->w-1), vbound(y+h-1,0,dest->h-1), vbound(x+w-1,0, dest->w-1), *c4);
246 vline(dest, vbound(x+w-1,0,dest->w-1), vbound(y,0,dest->h-1), vbound(y+h-2,0,dest->h-1), *c4);
247 }
248 }
249 void jwin_draw_frag_frame(BITMAP* dest, int x1, int y1, int w, int h, int fw, int fh, int style)
250 {
251 int c1,c2,c3,c4;
252
253 switch(style)
254 {
255 case FR_BOX:
256 c1 = jcLIGHT;
257 c2 = jcMEDLT;
258 c3 = jcMEDDARK;
259 c4 = jcDARK;
260 break;
261
262 case FR_INV:
263 c1 = jcDARK;
264 c2 = jcMEDDARK;
265 c3 = jcMEDLT;
266 c4 = jcLIGHT;
267 break;
268
269 case FR_DEEP:
270 c1 = jcMEDDARK;
271 c2 = jcDARK;
272 c3 = jcMEDLT;
273 c4 = jcLIGHT;
274 break;
275
276 case FR_DARK:
277 c1 = jcDARK;
278 c2 = jcMEDDARK;
279 c3 = jcMEDDARK;
280 c4 = jcDARK;
281 break;
282
283 case FR_ETCHED:
284 c1 = jcMEDDARK;
285 c2 = jcLIGHT;
286 c3 = jcMEDDARK;
287 c4 = jcLIGHT;
288 break;
289
290 case FR_MEDDARK:
291 c1 = jcMEDDARK;
292 c2 = jcBOX;
293 c3 = jcBOX;
294 c4 = jcMEDDARK;
295 break;
296
297 case FR_WIN:
298 default:
299 c1 = jcMEDLT;
300 c2 = jcLIGHT;
301 c3 = jcMEDDARK;
302 c4 = jcDARK;
303 break;
304 }
305
306 int xc = x1+fw-1;
307 int yc = y1+fh-1;
308 int x2 = x1+w-1;
309 int y2 = y1+h-1;
310
311 rectfill(dest, x1, y1, x2, yc, vc(0));
312 rectfill(dest, x1, yc, xc, y2, vc(0));
313
314 hline(dest, x1-2, y1-2, x2+2, scheme[c1]);
315 hline(dest, x1-1, y1-1, x2+1, scheme[c2]);
316
317 vline(dest, x1-2, y1-2, y2+2, scheme[c1]);
318 vline(dest, x1-1, y1-1, y2+1, scheme[c2]);
319
320 hline(dest, x1-2, y2+2, xc+2, scheme[c3]);
321 hline(dest, x1-1, y2+1, xc+1, scheme[c4]);
322
323 vline(dest, x2+2, y1-2, yc+2, scheme[c3]);
324 vline(dest, x2+1, y1-1, yc+1, scheme[c4]);
325
326 hline(dest, xc+2, yc+2, x2+2, scheme[c3]);
327 hline(dest, xc+1, yc+1, x2+1, scheme[c4]);
328
329 vline(dest, xc+2, yc+2, y2+2, scheme[c3]);
330 vline(dest, xc+1, yc+1, y2+1, scheme[c4]);
331 }
332 void jwin_draw_minimap_frame(BITMAP *dest,int x,int y,int w,int h,int scrsz,int style)
333 {
334 jwin_draw_frag_frame(dest,x,y,w,h,scrsz*8,scrsz*8,style);
335 }
336
337 /* jwin_draw_win:
338 * Draws a window -- a box with a frame.
339 */
340 void jwin_draw_win(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t frame)
341 {
342 rectfill(dest,zc_max(x,0),zc_max(y,0),zc_min(x+w-1, dest->w-1),zc_min(y+h-1, dest->h-1),scheme[jcBOX]);
343 jwin_draw_frame(dest, x, y, w, h, frame);
344 }
345
346 /* jwin_draw_button:
347 * Helper function for buttons.
348 * Draws a box with a frame that depends on "state":
349 * 0: normal border (slightly different than window border)
350 * 1: inverted border
351 * 2: dark border
352 * 3: medium dark border
353 */
354 void jwin_draw_button(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t state,int32_t type)
355 {
356 int32_t frame = FR_BOX;
357
358 if(type==1)
359 {
360 frame=FR_WIN;
361 }
362
363 switch(state)
364 {
365 case 1:
366 frame = FR_INV;
367 break;
368
369 case 2:
370 frame = FR_DARK;
371 break;
372
373 case 3:
374 frame = FR_MEDDARK;
375 break;
376 }
377
378 jwin_draw_win(dest, x, y, w, h, frame);
379 }
380
381 /* mix_value:
382 * Returns a mix of the values c1 and c2 with pos==0 being c1,
383 * pos==max being c2, pos==max/2 being half way between c1 and c2, etc.
384 */
385 int32_t mix_value(int32_t c1,int32_t c2,int32_t pos,int32_t max)
386 {
387 if(max<=0)
388 return c1;
389
390 return (c2 - c1) * pos / max + c1;
391 }
392
393 /* mix_color:
394 * Returns a mix of the colors c1 and c2 with pos==0 being c1,
395 * pos==max being c2, pos==max/2 being half way between c1 and c2, etc.
396 *
397 static int32_t mix_color(int32_t c1,int32_t c2,int32_t pos,int32_t max)
398 {
399 int32_t c;
400
401 if(bitmap_color_depth(screen) == 8)
402 c = mix_value(c1, c2, pos, max);
403 else
404 {
405 int32_t r = mix_value(getr(c1), getr(c2), pos, max);
406 int32_t g = mix_value(getg(c1), getg(c2), pos, max);
407 int32_t b = mix_value(getb(c1), getb(c2), pos, max);
408 c = makecol(r,g,b);
409 }
410
411 return c;
412 }
413 */
414
415 char *shorten_string(char *dest, char const* src, FONT *usefont, int32_t maxchars, int32_t maxwidth)
416 {
417 strncpy(dest,src,maxchars);
418 dest[maxchars-1]='\0';
419 int32_t len=(int32_t)strlen(dest);
420 int32_t width=text_length(usefont, dest);
421 dest[len]=0;
422
423 while(width>maxwidth && len>4)
424 {
425 dest[len-4] = '.';
426 dest[len-3] = '.';
427 dest[len-2] = '.';
428 dest[len-1] = 0;
429 len--;
430 width=text_length(usefont, dest);
431 }
432
433 return dest;
434 }
435
436 void jwin_draw_titlebar(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, const char *str, bool draw_button, bool helpbtn)
437 {
438 char buf[512];
439 int32_t len = (int32_t)strlen(str);
440 int32_t length = text_length(font,str);
441 int32_t height = text_height(font);
442
443 int32_t tx = x + 2;
444 int32_t ty = y + (h-height)/2;
445 PALETTE temp_pal;
446 get_palette(temp_pal);
447 dither_rect(dest, &temp_pal, x, y, x+w-1, y+h-1,
448 makecol15(temp_pal[scheme[jcTITLEL]].r,
449 temp_pal[scheme[jcTITLEL]].g,
450 temp_pal[scheme[jcTITLEL]].b),
451 makecol15(temp_pal[scheme[jcTITLER]].r,
452 temp_pal[scheme[jcTITLER]].g,
453 temp_pal[scheme[jcTITLER]].b),
454 scheme[jcTITLEL], scheme[jcTITLER]);
455
456
457 if(len>509)
458 len=509;
459
460 strncpy(buf,str,len);
461 buf[len]=0;
462
463 // this part needs work
464
465 if(length>w-20)
466 {
467 while(length>w-20 && len>1)
468 {
469 buf[len-4] = '.';
470 buf[len-3] = '.';
471 buf[len-2] = '.';
472 buf[len-1] = 0;
473 len--;
474 length = text_length(font,buf);
475 }
476 }
477
478 textout_ex(dest,font,buf,tx,ty,scheme[jcTITLEFG],-1);
479
480 if(draw_button)
481 {
482 draw_x_button(dest, x + w - 18, y+2, 0);
483 }
484
485 if(helpbtn)
486 {
487 draw_question_button(dest, x + w - (draw_button ? 36 : 18), y+2, 0);
488 }
489
490 }
491
492 void draw_question_button(BITMAP* dest, int32_t x, int32_t y, int32_t state)
493 {
494 int32_t c = scheme[jcBOXFG];
495
496 jwin_draw_button(dest,x,y,16,14,state,0);
497 x += 4 + (state?1:0);
498 y += 3 + (state?1:0);
499
500 line(dest, x+2, y+0, x+5, y+0, c);
501 line(dest, x+1, y+1, x+2, y+1, c);
502 line(dest, x+5, y+1, x+6, y+1, c);
503 line(dest, x+4, y+2, x+5, y+2, c);
504 line(dest, x+3, y+3, x+4, y+3, c);
505 line(dest, x+3, y+4, x+4, y+4, c);
506 line(dest, x+3, y+6, x+4, y+6, c);
507 line(dest, x+3, y+7, x+4, y+7, c);
508 }
509
510 void draw_x_button(BITMAP *dest, int32_t x, int32_t y, int32_t state)
511 {
512 int32_t c = scheme[jcBOXFG];
513
514 jwin_draw_button(dest,x,y,16,14,state,0);
515 x += 4 + (state?1:0);
516 y += 3 + (state?1:0);
517
518 line(dest,x, y, x+6,y+6,c);
519 line(dest,x+1,y, x+7,y+6,c);
520 line(dest,x, y+6,x+6,y, c);
521 line(dest,x+1,y+6,x+7,y, c);
522 }
523
524 void draw_arrow(BITMAP *dest, int c, int x, int y, int h, bool up, bool center)
525 {
526 if(!center)
527 x += h-1;
528 for(int i = 0; i<h; i++)
529 hline(dest, x-(up?i:h-i-1), y+i, x+(up?i:h-i-1), c);
530 }
531 void draw_arrow_horz(BITMAP *dest, int c, int x, int y, int w, bool left, bool center)
532 {
533 if(!center)
534 y += w-1;
535 for(int i = 0; i<w; i++)
536 vline(dest, x+i, y-(left?i:w-i-1), y+(left?i:w-i-1), c);
537 }
538 void draw_arrow_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int32_t up, int32_t state)
539 {
540 int32_t c = scheme[jcDARK];
541 int32_t ah = zc_min(h/3, 5);
542 int32_t i = 0;
543
544 jwin_draw_button(dest,x,y,w,h,state,1);
545 x += w/2 - (state?0:1);
546 y += (h-ah)/2 + (state?1:0);
547
548 for(; i<ah; i++)
549 {
550 hline(dest, x-(up?i:ah-i-1), y+i, x+(up?i:ah-i-1), c);
551 }
552 }
553
554 void draw_arrow_button_horiz(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int32_t up, int32_t state)
555 {
556 int32_t c = scheme[jcDARK];
557 int32_t aw = zc_min(w/3, 5);
558 int32_t i = 0;
559
560 jwin_draw_button(dest,x,y,w,h,state,1);
561 y += h/2 - (state?0:1);
562 x += (w-aw)/2 + (state?1:0);
563
564 for(; i<aw; i++)
565 {
566 vline(dest, x+i,y-(up?i:aw-i-1), y+(up?i:aw-i-1), c);
567 }
568 }
569
570 int32_t mouse_in_rect(int32_t x,int32_t y,int32_t w,int32_t h)
571 {
572 return ((gui_mouse_x() >= x) && (gui_mouse_y() >= y) &&
573 (gui_mouse_x() < x + w) && (gui_mouse_y() < y + h));
574 }
575
576 static int32_t jwin_do_x_button(BITMAP *dest, int32_t x, int32_t y)
577 {
578 int32_t down=0, last_draw = 0;
579
580 while(gui_mouse_b())
581 {
582 down = mouse_in_rect(x,y,16,14);
583
584 if(down!=last_draw)
585 {
586 draw_x_button(dest,x,y,down);
587 last_draw = down;
588 }
589
590 /* let other objects continue to animate */
591 broadcast_dialog_message(MSG_IDLE, 0);
592 rest(1);
593 }
594
595 if(down)
596 {
597 draw_x_button(dest,x,y,0);
598 }
599
600 return down;
601 }
602
603 /* dotted_rect:
604 * Draws a dotted rectangle, for showing an object has the input focus.
605 */
606 void dotted_rect(BITMAP *dest, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t fg, int32_t bg)
607 {
608 int32_t x = ((x1+y1) & 1) ? 1 : 0;
609 int32_t c;
610
611 //acquire the bitmap ourselves, because locking a surface within each call is *SLOW AS BALLS* -DD
612 acquire_bitmap(dest);
613
614 for(c=x1; c<=x2; c++)
615 {
616 putpixel(dest, c, y1, (((c+y1) & 1) == x) ? fg : bg);
617 putpixel(dest, c, y2, (((c+y2) & 1) == x) ? fg : bg);
618 }
619
620 for(c=y1+1; c<y2; c++)
621 {
622 putpixel(dest, x1, c, (((c+x1) & 1) == x) ? fg : bg);
623 putpixel(dest, x2, c, (((c+x2) & 1) == x) ? fg : bg);
624 }
625
626 release_bitmap(dest);
627
628 }
629
630 static void _dotted_rect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t fg, int32_t bg)
631 {
632 dotted_rect(screen, x1, y1, x2, y2, fg, bg);
633 }
634
635 static bool no_hline = false;
636 /* gui_textout_ln:
637 * Wrapper function for drawing text to the screen, which interprets the
638 * & character as an underbar for displaying keyboard shortcuts. Returns
639 * the width of the output string in pixels.
640 *
641 * Handles '\n' characters.
642 */
643 4 int32_t gui_textout_ln(BITMAP *bmp, FONT *f, unsigned const char *s, int32_t x, int32_t y, int32_t color, int32_t bg, int32_t pos)
644 {
645 char tmp[1024];
646 4 int32_t c = 0;
647 int32_t len;
648 4 int32_t pix_len = 0;
649 4 int32_t max_len = 0;
650 int32_t hline_pos;
651 4 int32_t xx = x;
652 4 bool is_scr = bmp == screen;
653
654
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
14 while(s[c])
655 {
656 10 len = 0;
657 10 hline_pos = -1;
658
659
4/4
✓ Branch 0 taken 532 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 532 times.
536 for(; (s[c]) && (len<(int32_t)(sizeof(tmp)-1)); c++)
660 {
661
2/2
✓ Branch 0 taken 526 times.
✓ Branch 1 taken 6 times.
532 if(s[c] == '\n')
662 {
663 6 c++;
664 6 break;
665 }
666
2/4
✓ Branch 0 taken 526 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 526 times.
✗ Branch 3 not taken.
526 else if(!no_hline && s[c] == '&')
667 {
668 if(s[c+1] != '&')
669 hline_pos = len;
670 else
671 {
672 tmp[len++] = '&';
673 c++;
674 }
675 }
676 else
677 526 tmp[len++] = s[c];
678 526 }
679
680 10 tmp[len] = 0;
681 10 pix_len = text_length(f, tmp);
682
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
10 if (pix_len > max_len) max_len = pix_len;
683 10 x = xx;
684
685
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if(pos==1) //center
686 {
687 x -= pix_len / 2;
688 }
689
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 else if(pos==2) //right
690 {
691 x -= pix_len;
692 }
693
694
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if(bmp)
695 {
696 10 textout_ex(bmp, f, tmp, x, y, color,bg);
697
698
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if(hline_pos >= 0)
699 {
700 int32_t i;
701 i = tmp[hline_pos];
702 tmp[hline_pos] = 0;
703 hline_pos = text_length(f, tmp);
704 tmp[0] = i;
705 tmp[1] = 0;
706 i = text_length(f, tmp);
707 hline(bmp, x+hline_pos, y+text_height(f)-gui_font_baseline, x+hline_pos+i-1, color);
708 }
709 10 }
710
711 10 y += text_height(f);
712 }
713 4 return max_len;
714 }
715
716 4 int32_t gui_textout_ln(BITMAP *bmp, unsigned const char *s, int32_t x, int32_t y, int32_t color, int32_t bg, int32_t pos)
717 {
718 4 return gui_textout_ln(bmp, font, s, x, y, color, bg, pos);
719 }
720
721 int32_t gui_text_width(FONT *f, const char *s)
722 {
723 return gui_textout_ln(NULL, f, (uint8_t*)s, 0, 0, 0, 0, 0);
724 }
725
726 4 int32_t count_newline(uint8_t *s)
727 {
728 4 int32_t cnt = 0;
729
2/2
✓ Branch 0 taken 532 times.
✓ Branch 1 taken 4 times.
536 for(int32_t q = 0; s[q] != 0; ++q)
730 {
731
2/2
✓ Branch 0 taken 526 times.
✓ Branch 1 taken 6 times.
532 if(s[q] == '\n') ++cnt;
732 532 }
733 4 return cnt;
734 }
735
736 4 int32_t gui_textheight(FONT* f, uint8_t *s)
737 {
738 4 return text_height(f) * (count_newline(s) + 1);
739 }
740
741 4 int32_t gui_textheight(uint8_t* s)
742 {
743 4 return gui_textheight(font, s);
744 }
745
746 /* typedef for the listbox callback functions */
747 typedef char *(*getfuncptr)(int32_t, int32_t *);
748
749 /* event handler that closes a dialog */
750 int32_t close_dlg()
751 {
752 return D_CLOSE;
753 }
754
755 int32_t jwin_frame_proc(int32_t msg, DIALOG *d, int32_t c)
756 {
757 //these are here to bypass compiler warnings about unused arguments
758 c=c;
759
760 if(msg == MSG_DRAW)
761 {
762 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, d->d1);
763 }
764
765 return D_O_K;
766 }
767
768 int32_t jwin_guitest_proc(int32_t msg, DIALOG *d, int32_t c)
769 {
770 //these are here to bypass compiler warnings about unused arguments
771 c=c;
772
773 if(msg == MSG_DRAW)
774 {
775 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, d->d1);
776 }
777
778 return D_O_K;
779 }
780
781 /* jwin_win_proc:
782 * Draws a box with a frame. Use dp for a title string. If dp is NULL,
783 * it won't draw a title bar. If the D_EXIT flag is set, it will also
784 * draw an "X" button on the title bar that can be used to close the
785 * dialog.
786 * If d->dp3 is non-null, it will be read as a help text string, and
787 * a ? button will be drawn, that upon clicking will display the helptext.
788 */
789 int32_t jwin_win_proc(int32_t msg, DIALOG *d, int32_t c)
790 {
791 //these are here to bypass compiler warnings about unused arguments
792 c=c;
793
794 rest(1);
795 static bool skipredraw = false;
796
797 switch(msg)
798 {
799 case MSG_DRAW:
800 if(skipredraw)
801 {
802 skipredraw = false;
803 break;
804 }
805 jwin_draw_win(screen, d->x, d->y, d->w, d->h, FR_WIN);
806
807 if(d->dp)
808 {
809 FONT *oldfont = font;
810
811 if(d->dp2)
812 {
813 font = (FONT*)d->dp2;
814 }
815
816 jwin_draw_titlebar(screen, d->x+3, d->y+3, d->w-6, 18, (char*)d->dp, d->flags & D_EXIT, d->dp3!=NULL);
817 font = oldfont;
818 }
819 break;
820
821 case MSG_WANTFOCUS:
822 if(gui_mouse_b())
823 return D_WANTFOCUS|D_REDRAW;
824 else return D_O_K;
825 case MSG_GOTFOCUS:
826 case MSG_LOSTFOCUS:
827 skipredraw = true;
828 return D_O_K;
829
830 case MSG_CLICK:
831 {
832 if((d->flags & D_EXIT) && mouse_in_rect(d->x+d->w-21, d->y+5, 16, 14))
833 {
834 if(jwin_do_x_button(screen, d->x+d->w-21, d->y+5))
835 {
836 GUI_EVENT(d, geCLOSE);
837 return D_CLOSE;
838 }
839 }
840 if(char const* helpstr = (char const*)d->dp3)
841 {
842 if(mouse_in_rect(d->x+d->w-((d->flags&D_EXIT)?39:21), d->y+5, 16, 14))
843 {
844 broadcast_dialog_message(MSG_DRAW,0);
845 InfoDialog("Info", helpstr).show();
846 }
847 }
848 }
849 break;
850 }
851
852 return D_O_K;
853 }
854
855 /* jwin_text_proc:
856 * Simple dialog procedure: draws the text string which is pointed to by dp.
857 *
858 * Handles '\n' characters.
859 */
860 4 int32_t jwin_text_proc(int32_t msg, DIALOG *d, int32_t)
861 {
862 ASSERT(d);
863
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 static BITMAP *dummy=create_bitmap_ex(8, 1, 1);
864
865
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 switch(msg)
866 {
867 case MSG_START:
868 {
869 4 FONT *oldfont = font;
870
871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(d->dp2)
872 {
873 4 font = (FONT*)d->dp2;
874 4 }
875
876 4 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 0);
877 4 d->h=gui_textheight((uint8_t *)d->dp);
878
879 4 font = oldfont;
880 4 break;
881 }
882 case MSG_DRAW:
883 {
884 FONT *oldfont = font;
885
886 if(d->dp2)
887 {
888 font = (FONT*)d->dp2;
889 }
890
891 if(d->flags & D_DISABLED)
892 {
893 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 0);
894 d->w=gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 0);
895 }
896 else
897 {
898 d->w=gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 0);
899 }
900
901 font = oldfont;
902 break;
903 }
904 }
905
906 4 return D_O_K;
907 }
908
909 int32_t jwin_ctext_proc(int32_t msg, DIALOG *d, int32_t)
910 {
911 ASSERT(d);
912 static BITMAP *dummy=create_bitmap_ex(8, 320, 240);
913
914 switch(msg)
915 {
916 case MSG_START:
917 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 0);
918 break;
919
920 case MSG_DRAW:
921 FONT *oldfont = font;
922
923 if(d->dp2)
924 {
925 font = (FONT*)d->dp2;
926 }
927
928 if(d->flags & D_DISABLED)
929 {
930 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 1);
931 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 1);
932 }
933 else
934 {
935 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 1);
936 }
937
938 font = oldfont;
939 break;
940 }
941
942 return D_O_K;
943 }
944
945 int32_t jwin_rtext_proc(int32_t msg, DIALOG *d, int32_t)
946 {
947 ASSERT(d);
948 static BITMAP *dummy=create_bitmap_ex(8, 1, 1);
949
950 switch(msg)
951 {
952 case MSG_START:
953 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 2);
954 break;
955
956 case MSG_DRAW:
957 FONT *oldfont = font;
958
959 if(d->dp2)
960 {
961 font = (FONT*)d->dp2;
962 }
963
964 if(d->flags & D_DISABLED)
965 {
966 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 2);
967 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 2);
968 }
969 else
970 {
971 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 2);
972 }
973
974 font = oldfont;
975 break;
976 }
977
978 return D_O_K;
979 }
980
981 int32_t d_ctext2_proc(int32_t msg, DIALOG *d, int32_t c)
982 {
983 auto ret = d_ctext_proc(msg, d, c);
984 return ret;
985 }
986
987 int32_t new_text_proc(int32_t msg, DIALOG *d, int32_t c)
988 {
989 BITMAP* oldscreen = screen;
990 if(msg==MSG_DRAW)
991 {
992 if(d->flags & D_HIDDEN) return D_O_K;
993 screen = create_bitmap_ex(8,oldscreen->w,oldscreen->h);
994 clear_bitmap(screen);
995 set_clip_rect(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1);
996 }
997 int32_t ret = D_O_K;
998 int32_t w = d->w, h = d->h, x = d->x, y = d->y;
999 if(d->d2) no_hline = true;
1000 switch(d->d1)
1001 {
1002 case 0:
1003 ret = jwin_text_proc(msg, d, c);
1004 break;
1005 case 1:
1006 d->x += d->w/2;
1007 ret = jwin_ctext_proc(msg, d, c);
1008 break;
1009 case 2:
1010 d->x += d->w - 1;
1011 ret = jwin_rtext_proc(msg, d, c);
1012 break;
1013 }
1014 no_hline = false;
1015 d->w = w;
1016 d->h = h;
1017 d->x = x;
1018 d->y = y;
1019 if(msg==MSG_DRAW)
1020 {
1021 masked_blit(screen, oldscreen, d->x, d->y, d->x, d->y, d->w, d->h);
1022 destroy_bitmap(screen);
1023 screen = oldscreen;
1024 }
1025 if(msg==MSG_WANTFOCUS && gui_mouse_b())
1026 ret |= D_WANTFOCUS|D_REDRAW;
1027 return ret;
1028 }
1029
1030 /* draw_text_button:
1031 * Helper for jwin_button_proc.
1032 */
1033 void jwin_draw_text_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, const char *str, int32_t flags, bool show_dotted_rect)
1034 {
1035 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1036
1037 if(flags & D_SELECTED)
1038 {
1039 jwin_draw_button(dest, x, y, w, h, 2, 0);
1040 flags &= ~D_DISABLED;
1041 }
1042 else if(!(flags & D_GOTFOCUS))
1043 jwin_draw_button(dest, x, y, w, h, 0, 0);
1044 else
1045 {
1046 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1047 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1048 }
1049
1050 bool drawstring = true;
1051 if(str[1]==0 && byte(str[0]) >= 0x80)
1052 {
1053 drawstring = false;
1054 int col = jwin_pal[(flags & D_DISABLED) ? jcLIGHT : jcBOXFG];
1055 int aw = w/4, ah = h/4;
1056 int woff = (aw/2)+1, hoff = (ah/2)+1;
1057 int x1 = x+w/2, x2 = x+(w-aw)/2;
1058 int y1 = y+(h-aw)/2, y2 = y+h/2;
1059 switch(byte(str[0]))
1060 {
1061 case 0x88:
1062 draw_arrow(dest, col, x1, y1, ah, true, true);
1063 break;
1064 case 0x89:
1065 draw_arrow(dest, col, x1, y1, ah, false, true);
1066 break;
1067 case 0x8A:
1068 draw_arrow_horz(dest, col, x2, y2, aw, true, true);
1069 break;
1070 case 0x8B:
1071 draw_arrow_horz(dest, col, x2, y2, aw, false, true);
1072 break;
1073 case 0x98:
1074 draw_arrow(dest, col, x1, y1-hoff, ah, false, true);
1075 draw_arrow(dest, col, x1, y1+hoff, ah, true, true);
1076 break;
1077 case 0x99:
1078 draw_arrow(dest, col, x1, y1-hoff, ah, true, true);
1079 draw_arrow(dest, col, x1, y1+hoff, ah, false, true);
1080 break;
1081 case 0x9A:
1082 draw_arrow_horz(dest, col, x2-woff, y2, aw, false, true);
1083 draw_arrow_horz(dest, col, x2+woff, y2, aw, true, true);
1084 break;
1085 case 0x9B:
1086 draw_arrow_horz(dest, col, x2-woff, y2, aw, true, true);
1087 draw_arrow_horz(dest, col, x2+woff, y2, aw, false, true);
1088 break;
1089 default: drawstring = true;
1090 }
1091 }
1092 if(drawstring)
1093 {
1094 if(!(flags & D_DISABLED))
1095 gui_textout_ex(dest, str, x+w/2+g, y+(h-text_height(font))/2+g, scheme[jcBOXFG], -1, TRUE);
1096 else
1097 {
1098 gui_textout_ex(dest, str, x+w/2+1,y+(h-text_height(font))/2+1, scheme[jcLIGHT], -1, TRUE);
1099 gui_textout_ex(dest, str, x+w/2, y+(h-text_height(font))/2, scheme[jcDISABLED_FG], -1, TRUE);
1100 }
1101 }
1102
1103 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1104 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1105 }
1106
1107 int icon_proportion(int icon,int s1,int s2)
1108 {
1109 int sz = round(sqrt(zc_min(s1,s2))*1.25);
1110 switch(icon)
1111 {
1112 case BTNICON_STOPSQUARE:
1113 sz += 4;
1114 break;
1115 case BTNICON_PLUS:
1116 case BTNICON_MINUS:
1117 sz += 4;
1118 break;
1119 }
1120 return sz;
1121 }
1122 void jwin_draw_icon_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int icon, int32_t flags, bool show_dotted_rect)
1123 {
1124 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1125
1126 if(flags & D_SELECTED)
1127 jwin_draw_button(dest, x, y, w, h, 2, 0);
1128 else if(!(flags & D_GOTFOCUS))
1129 jwin_draw_button(dest, x, y, w, h, 0, 0);
1130 else
1131 {
1132 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1133 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1134 }
1135
1136 int col = jwin_pal[(flags & D_DISABLED) ? jcLIGHT : jcBOXFG];
1137 jwin_draw_icon(dest,x+w/2,y+h/2,col,icon,icon_proportion(icon,w,h),true);
1138
1139 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1140 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1141 }
1142 void jwin_draw_icon(BITMAP *dest, int x, int y, int col, int icon, int asz, bool center)
1143 {
1144 jwin_draw_icon(dest,x,y,col,icon,asz,asz,center);
1145 }
1146 void jwin_draw_icon(BITMAP *dest, int x, int y, int col, int icon, int aw, int ah, bool center)
1147 {
1148 int w2 = aw, h2 = ah;
1149 int sz = zc_min(aw,ah);
1150 switch(icon)
1151 {
1152 case BTNICON_ARROW_LEFT2:
1153 case BTNICON_ARROW_RIGHT2:
1154 aw *= 2;
1155 ah = aw*2-1;
1156 break;
1157 case BTNICON_ARROW_LEFT3:
1158 case BTNICON_ARROW_RIGHT3:
1159 aw *= 3;
1160 ah = aw*2-1;
1161 break;
1162 case BTNICON_ARROW_UP:
1163 case BTNICON_ARROW_DOWN:
1164 case BTNICON_CONTRACT_VERT:
1165 case BTNICON_EXPAND_VERT:
1166 aw = ah*2-1;
1167 break;
1168 case BTNICON_ARROW_LEFT:
1169 case BTNICON_ARROW_RIGHT:
1170 case BTNICON_CONTRACT_HORZ:
1171 case BTNICON_EXPAND_HORZ:
1172 ah = aw*2-1;
1173 break;
1174 case BTNICON_STOPSQUARE:
1175 aw = ah = sz;
1176 break;
1177 case BTNICON_PLUS:
1178 if(!(sz%2)) ++sz;
1179 aw = ah = w2 = h2 = sz;
1180 w2 /= 3;
1181 h2 /= 3;
1182 if(!(h2%2)) ++h2;
1183 if(!(w2%2)) ++w2;
1184 break;
1185 case BTNICON_MINUS:
1186 if(!(sz%2)) ++sz;
1187 aw = ah = w2 = h2 = sz;
1188 h2 /= 3;
1189 if(!(h2%2)) ++h2;
1190 break;
1191 }
1192 int woff = (aw/2)+1, hoff = (ah/2)+1;
1193 int cx = center ? (x-aw/2) : x,
1194 cy = center ? (y-ah/2) : y;
1195 switch(icon)
1196 {
1197 case BTNICON_ARROW_UP:
1198 draw_arrow(dest, col, x, cy, ah, true, center);
1199 break;
1200 case BTNICON_ARROW_DOWN:
1201 draw_arrow(dest, col, x, cy, ah, false, center);
1202 break;
1203 case BTNICON_ARROW_LEFT:
1204 draw_arrow_horz(dest, col, cx, y, aw, true, center);
1205 break;
1206 case BTNICON_ARROW_RIGHT:
1207 draw_arrow_horz(dest, col, cx, y, aw, false, center);
1208 break;
1209 case BTNICON_CONTRACT_VERT:
1210 draw_arrow(dest, col, x, cy-hoff, ah, false, center);
1211 draw_arrow(dest, col, x, cy+hoff, ah, true, center);
1212 break;
1213 case BTNICON_EXPAND_VERT:
1214 draw_arrow(dest, col, x, cy-hoff, ah, true, center);
1215 draw_arrow(dest, col, x, cy+hoff, ah, false, center);
1216 break;
1217 case BTNICON_CONTRACT_HORZ:
1218 draw_arrow_horz(dest, col, cx-woff, y, aw, false, center);
1219 draw_arrow_horz(dest, col, cx+woff, y, aw, true, center);
1220 break;
1221 case BTNICON_EXPAND_HORZ:
1222 draw_arrow_horz(dest, col, cx-woff, y, aw, true, center);
1223 draw_arrow_horz(dest, col, cx+woff, y, aw, false, center);
1224 break;
1225 case BTNICON_ARROW_LEFT2:
1226 draw_arrow_horz(dest, col, cx, y, w2, true, center);
1227 draw_arrow_horz(dest, col, cx+w2, y, w2, true, center);
1228 break;
1229 case BTNICON_ARROW_LEFT3:
1230 draw_arrow_horz(dest, col, cx, y, w2, true, center);
1231 draw_arrow_horz(dest, col, cx+w2, y, w2, true, center);
1232 draw_arrow_horz(dest, col, cx+w2*2, y, w2, true, center);
1233 break;
1234 case BTNICON_ARROW_RIGHT2:
1235 draw_arrow_horz(dest, col, cx, y, w2, false, center);
1236 draw_arrow_horz(dest, col, cx+w2, y, w2, false, center);
1237 break;
1238 case BTNICON_ARROW_RIGHT3:
1239 draw_arrow_horz(dest, col, cx, y, w2, false, center);
1240 draw_arrow_horz(dest, col, cx+w2, y, w2, false, center);
1241 draw_arrow_horz(dest, col, cx+w2*2, y, w2, false, center);
1242 break;
1243 case BTNICON_STOPSQUARE:
1244 rectfill(dest, cx, cy, cx+aw-1, cy+ah-1, col);
1245 break;
1246 case BTNICON_MINUS:
1247 rectfill(dest, cx, cy+(ah/2)-(h2/2), cx+aw-1, cy+(ah/2)+(h2/2), col);
1248 break;
1249 case BTNICON_PLUS:
1250 rectfill(dest, cx, cy+(ah/2)-(h2/2), cx+aw-1, cy+(ah/2)+(h2/2), col);
1251 rectfill(dest, cx+(aw/2)-(w2/2), cy, cx+(aw/2)+(w2/2), cy+ah-1, col);
1252 break;
1253 }
1254 }
1255 /* draw_graphics_button:
1256 * Helper for jwin_button_proc.
1257 */
1258 void jwin_draw_graphics_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, BITMAP *bmp, BITMAP *bmp2, int32_t flags, bool show_dotted_rect, bool overlay)
1259 {
1260 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1261
1262 if(flags & D_SELECTED)
1263 jwin_draw_button(dest, x, y, w, h, 2, 0);
1264 else if(!(flags & D_GOTFOCUS))
1265 jwin_draw_button(dest, x, y, w, h, 0, 0);
1266 else
1267 {
1268 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1269 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1270 }
1271
1272 if(!(flags & D_DISABLED))
1273 {
1274 // gui_textout_ex(dest, str, x+w/2+g, y+h/2-text_height(font)/2+g, scheme[jcBOXFG], -1, TRUE);
1275 if(bmp!=NULL)
1276 {
1277 if(overlay)
1278 {
1279 masked_blit(bmp, dest, 0, 0, x+w/2-bmp->w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1280 }
1281 else
1282 {
1283 blit(bmp, dest, 0, 0, x+w/2-bmp->w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1284 }
1285 }
1286 }
1287 else
1288 {
1289 // gui_textout_ex(dest, str, x+w/2+1,y+h/2-text_height(font)/2+1, scheme[jcLIGHT], -1, TRUE);
1290 // gui_textout_ex(dest, str, x+w/2, y+h/2-text_height(font)/2, scheme[jcMEDDARK], -1, TRUE);
1291 if(bmp2!=NULL)
1292 {
1293 if(overlay)
1294 {
1295 masked_blit(bmp2, dest, 0, 0, x+w/2-bmp2->w/2+g, y+h/2-bmp2->h/2+g, bmp2->h, bmp2->w);
1296 }
1297 else
1298 {
1299 blit(bmp2, dest, 0, 0, x+w/2-bmp2->w/2+g, y+h/2-bmp2->h/2+g, bmp2->h, bmp2->w);
1300 }
1301 }
1302 }
1303
1304 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1305 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1306 }
1307
1308 /* jwin_button_proc:
1309 * A button object (the dp field points to the text string). This object
1310 * can be selected by clicking on it with the mouse or by pressing its
1311 * keyboard shortcut. If the D_EXIT flag is set, selecting it will close
1312 * the dialog, otherwise it will toggle on and off.
1313 */
1314 int32_t jwin_button_proc(int32_t msg, DIALOG *d, int32_t)
1315 {
1316 int32_t down=0;
1317 int32_t selected=(d->flags&D_SELECTED)?1:0;
1318 int32_t disabled=(d->flags&D_DISABLED)?1:0;
1319 int32_t last_draw;
1320
1321 switch(msg)
1322 {
1323 case MSG_DRAW:
1324 {
1325 FONT *oldfont = font;
1326
1327 if(d->dp2)
1328 {
1329 font = (FONT*)d->dp2;
1330 }
1331
1332 jwin_draw_text_button(screen, d->x, d->y, d->w, d->h, (char*)d->dp, d->flags, true);
1333 font = oldfont;
1334 }
1335 break;
1336
1337 case MSG_WANTFOCUS:
1338 return D_WANTFOCUS;
1339
1340 case MSG_KEY:
1341 if(disabled) break;
1342 /* close dialog? */
1343 if(d->flags & D_EXIT)
1344 {
1345 return D_CLOSE;
1346 }
1347 if(d->d2 == 1) //Insta-button
1348 {
1349 GUI_EVENT(d, geCLICK);
1350 break;
1351 }
1352 /* or just toggle */
1353 d->flags ^= D_SELECTED;
1354 GUI_EVENT(d, geCLICK);
1355 object_message(d, MSG_DRAW, 0);
1356 break;
1357
1358 case MSG_CLICK:
1359 {
1360 if(disabled) break;
1361 if(d->d2 == 1) //Insta-button
1362 {
1363 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1364 {
1365 GUI_EVENT(d, geCLICK);
1366 if(d->flags & D_EXIT)
1367 return D_CLOSE;
1368 }
1369 }
1370 else
1371 {
1372 last_draw = 0;
1373
1374 /* track the mouse until it is released */
1375 while(gui_mouse_b())
1376 {
1377 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1378
1379 /* redraw? */
1380 bool should_redraw = false;
1381 if(last_draw != down)
1382 {
1383 if(down != selected)
1384 d->flags |= D_SELECTED;
1385 else
1386 d->flags &= ~D_SELECTED;
1387
1388 object_message(d, MSG_DRAW, 0);
1389 last_draw = down;
1390 should_redraw = true;
1391 }
1392
1393 /* let other objects continue to animate */
1394 int r = broadcast_dialog_message(MSG_IDLE, 0);
1395 if (r & D_REDRAWME) should_redraw = true;
1396
1397 if (should_redraw)
1398 {
1399 update_hw_screen();
1400 }
1401 }
1402
1403 /* redraw in normal state */
1404 if(down)
1405 {
1406 GUI_EVENT(d, geCLICK);
1407 if(d->flags&D_EXIT)
1408 {
1409 d->flags &= ~D_SELECTED;
1410 object_message(d, MSG_DRAW, 0);
1411 }
1412 }
1413
1414 /* should we close the dialog? */
1415 if(down && (d->flags & D_EXIT))
1416 return D_CLOSE;
1417 }
1418 }
1419 break;
1420 }
1421 return D_O_K;
1422 }
1423 int32_t jwin_iconbutton_proc(int32_t msg, DIALOG *d, int32_t)
1424 {
1425 int32_t down=0;
1426 int32_t selected=(d->flags&D_SELECTED)?1:0;
1427 int32_t last_draw;
1428
1429 switch(msg)
1430 {
1431 case MSG_DRAW:
1432 {
1433 jwin_draw_icon_button(screen, d->x, d->y, d->w, d->h, d->d1, d->flags, true);
1434 }
1435 break;
1436
1437 case MSG_WANTFOCUS:
1438 return D_WANTFOCUS;
1439
1440 case MSG_KEY:
1441 /* close dialog? */
1442 if(d->flags & D_EXIT)
1443 {
1444 return D_CLOSE;
1445 }
1446 if(d->d2 == 1) //Insta-button
1447 {
1448 GUI_EVENT(d, geCLICK);
1449 break;
1450 }
1451 /* or just toggle */
1452 d->flags ^= D_SELECTED;
1453 GUI_EVENT(d, geCLICK);
1454 object_message(d, MSG_DRAW, 0);
1455 break;
1456
1457 case MSG_CLICK:
1458 {
1459 if(d->d2 == 1) //Insta-button
1460 {
1461 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1462 {
1463 GUI_EVENT(d, geCLICK);
1464 if(d->flags & D_EXIT)
1465 return D_CLOSE;
1466 }
1467 }
1468 else
1469 {
1470 last_draw = 0;
1471
1472 /* track the mouse until it is released */
1473 while(gui_mouse_b())
1474 {
1475 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1476
1477 /* redraw? */
1478 bool should_redraw = false;
1479 if(last_draw != down)
1480 {
1481 if(down != selected)
1482 d->flags |= D_SELECTED;
1483 else
1484 d->flags &= ~D_SELECTED;
1485
1486 object_message(d, MSG_DRAW, 0);
1487 last_draw = down;
1488 should_redraw = true;
1489 }
1490
1491 /* let other objects continue to animate */
1492 int r = broadcast_dialog_message(MSG_IDLE, 0);
1493 if (r & D_REDRAWME) should_redraw = true;
1494
1495 if (should_redraw)
1496 {
1497 update_hw_screen();
1498 }
1499 }
1500
1501 /* redraw in normal state */
1502 if(down)
1503 {
1504 GUI_EVENT(d, geCLICK);
1505 if(d->flags&D_EXIT)
1506 {
1507 d->flags &= ~D_SELECTED;
1508 object_message(d, MSG_DRAW, 0);
1509 }
1510 }
1511
1512 /* should we close the dialog? */
1513 if(down && (d->flags & D_EXIT))
1514 return D_CLOSE;
1515 }
1516 }
1517 break;
1518 }
1519 return D_O_K;
1520 }
1521 int32_t jwin_infobtn_proc(int32_t msg, DIALOG *d, int32_t)
1522 {
1523 int32_t down=0;
1524 int32_t selected=(d->flags&D_SELECTED)?1:0;
1525 int32_t last_draw;
1526 std::string* str = (std::string*)d->dp;
1527 bool dis = (d->flags & D_DISABLED) || !str || !((*str)[0]) || str->find_first_not_of(" \t")==std::string::npos;
1528 int flags = d->flags | (dis?D_DISABLED:0);
1529 bool show = false;
1530 switch(msg)
1531 {
1532 case MSG_DRAW:
1533 {
1534 FONT *oldfont = font;
1535
1536 if(d->dp2)
1537 font = (FONT*)d->dp2;
1538
1539 jwin_draw_text_button(screen, d->x, d->y, d->w, d->h, "?", flags, true);
1540 font = oldfont;
1541 }
1542 break;
1543
1544 case MSG_WANTFOCUS:
1545 if(dis) break;
1546 return D_WANTFOCUS;
1547
1548 case MSG_KEY:
1549 if(dis) break;
1550 show = true;
1551 break;
1552
1553 case MSG_CLICK:
1554 {
1555 if(dis) break;
1556 if(d->d2 == 1) //Insta-button
1557 {
1558 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1559 {
1560 show = true;
1561 break;
1562 }
1563 }
1564 else
1565 {
1566 last_draw = 0;
1567
1568 /* track the mouse until it is released */
1569 while(gui_mouse_b())
1570 {
1571 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1572
1573 /* redraw? */
1574 bool should_redraw = false;
1575 if(last_draw != down)
1576 {
1577 if(down != selected)
1578 d->flags |= D_SELECTED;
1579 else
1580 d->flags &= ~D_SELECTED;
1581
1582 object_message(d, MSG_DRAW, 0);
1583 last_draw = down;
1584 should_redraw = true;
1585 }
1586
1587 /* let other objects continue to animate */
1588 int r = broadcast_dialog_message(MSG_IDLE, 0);
1589 if (r & D_REDRAWME) should_redraw = true;
1590
1591 if (should_redraw)
1592 {
1593 update_hw_screen();
1594 }
1595 }
1596
1597 /* redraw in normal state */
1598 if(down)
1599 show = true;
1600 }
1601 }
1602 break;
1603 }
1604 if(show)
1605 {
1606 d->flags &= ~D_SELECTED;
1607 object_message(d, MSG_DRAW, 0);
1608 InfoDialog("Info",*str).show();
1609 GUI_EVENT(d, geCLICK);
1610 }
1611 return D_O_K;
1612 }
1613
1614 /* jwin_func_button_proc:
1615 * A button that runs a void() function when clicked.
1616 * dp: Button text
1617 * dp2: Function to run
1618 */
1619 int32_t jwin_func_button_proc(int32_t msg, DIALOG *d, int32_t c)
1620 {
1621 int32_t down=0;
1622 int32_t selected=(d->flags&D_SELECTED)?1:0;
1623 int32_t last_draw;
1624
1625 if(msg==MSG_CLICK || msg==MSG_KEY)
1626 {
1627 last_draw = 0;
1628
1629 /* track the mouse until it is released */
1630 while(gui_mouse_b())
1631 {
1632 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1633
1634 /* redraw? */
1635 bool should_redraw = false;
1636 if(last_draw != down)
1637 {
1638 if(down != selected)
1639 d->flags |= D_SELECTED;
1640 else
1641 d->flags &= ~D_SELECTED;
1642
1643 object_message(d, MSG_DRAW, 0);
1644 last_draw = down;
1645 should_redraw = true;
1646 }
1647
1648 /* let other objects continue to animate */
1649 int r = broadcast_dialog_message(MSG_IDLE, 0);
1650 if (r & D_REDRAWME) should_redraw = true;
1651
1652 if (should_redraw)
1653 {
1654 update_hw_screen();
1655 }
1656 }
1657
1658 /* redraw in normal state */
1659 if(down)
1660 {
1661 if(d->flags&D_EXIT)
1662 {
1663 d->flags &= ~D_SELECTED;
1664 object_message(d, MSG_DRAW, 0);
1665 }
1666 }
1667
1668 /* pop up and call the function */
1669 if(down)
1670 {
1671 d->flags &= ~D_SELECTED;
1672 object_message(d, MSG_DRAW, 0);
1673 typedef void (*funcType)(void);
1674 funcType func=reinterpret_cast<funcType>(d->dp3);
1675 func();
1676 }
1677
1678 return D_O_K;
1679 }
1680
1681 return jwin_button_proc(msg, d, c);
1682 }
1683
1684 /*(int32_t x = atoi(d->dp);
1685 if ( x > 256 )
1686 d->dp = (char*)"255";
1687 elseif (x < 0 ) d->dp = (char*)"0";
1688 */
1689
1690 int32_t jwin_vedit_proc(int32_t msg, DIALOG *d, int32_t c)
1691 {
1692 if(d->flags & D_HIDDEN)
1693 {
1694 switch(msg)
1695 {
1696 case MSG_CHAR: case MSG_UCHAR: case MSG_XCHAR: case MSG_DRAW: case MSG_CLICK: case MSG_DCLICK: case MSG_KEY: case MSG_WANTFOCUS:
1697 return D_O_K;
1698 }
1699 }
1700 if(d->h < 2+((text_height(d->dp2 ? (FONT*)d->dp2 : font)+2)*2))
1701 return jwin_edit_proc(msg, d, c);
1702 static char nullbuf[2];
1703 sprintf(nullbuf, " ");
1704 int32_t f, l, p, w, x, y, fg, bg;
1705 int32_t lastSpace = -1;
1706 char *s;
1707 char buf[2] = {0,0};
1708
1709 if(d->dp==NULL)
1710 {
1711 d->dp=(void *)nullbuf;
1712 }
1713
1714 s = (char*)d->dp;
1715 l = (int32_t)strlen(s);
1716
1717 int32_t cursor_start = d->d2 & 0x0000FFFF;
1718 int32_t cursor_end = int32_t((d->d2 & 0xFFFF0000) >> 16);
1719 // This was previously doing bitshifts on -1. There wasn't enough space so I cannibalized 0xFFFF instead. -Moosh
1720 if (cursor_start == 0xFFFF)
1721 cursor_start = -1;
1722 if (cursor_end == 0xFFFF)
1723 cursor_end = -1;
1724
1725 if(cursor_start > l)
1726 cursor_start = l;
1727 if(cursor_end > l)
1728 cursor_end = l;
1729 auto low_cursor = cursor_start<0 ? cursor_end : (cursor_end<0 ? cursor_start : (zc_min(cursor_start, cursor_end)));
1730 auto high_cursor = zc_max(cursor_start,cursor_end);
1731 bool multiselect = cursor_end > -1;
1732
1733 FONT *oldfont = font;
1734 if(d->dp2)
1735 font = (FONT*)d->dp2;
1736
1737 auto* char_length = font->vtable->char_length;
1738 std::vector<size_t> lines;
1739 x = 0;
1740
1741 y = d->y + 2;
1742 size_t ind = 0;
1743 int32_t yinc = text_height(font)+2;
1744 int32_t maxy = y;
1745 size_t maxlines = 1;
1746 while(maxy+yinc < d->y+d->h-3)
1747 {
1748 maxy += yinc;
1749 ++maxlines;
1750 }
1751 size_t half_width = (maxlines-1)/2;
1752 size_t line_scroll = 0;
1753 size_t focused_line = size_t(-1);
1754 size_t focused_line2 = size_t(-1);
1755 switch(msg)
1756 {
1757 //Only these messages need these calculations, so save processing.
1758 case MSG_DRAW:
1759 case MSG_CLICK:
1760 case MSG_CHAR:
1761 {
1762 for(auto q = 0; q <= l; ++q)
1763 {
1764 char c = s[q] ? s[q] : ' ';
1765 x += char_length(font, c);
1766 if(x > d->w - 6)
1767 {
1768 // Line's too long, break
1769 if(lastSpace >= 0)
1770 {
1771 q = lastSpace+1;
1772 lines.push_back(q);
1773 lastSpace = -1;
1774 }
1775 else
1776 {
1777 lines.push_back(q);
1778 }
1779 x = 0;
1780 --q; //counteract increment
1781 }
1782 else if(c == ' ')
1783 lastSpace = q;
1784 }
1785 if(lines.empty() || lines.back() != l+1)
1786 lines.push_back(l+1);
1787 for(size_t line = 0; line < lines.size(); ++line)
1788 {
1789 if(size_t(multiselect ? cursor_end : cursor_start) < lines[line]) //should ALWAYS execute once
1790 {
1791 focused_line = line;
1792 break;
1793 }
1794 }
1795 if(!multiselect)
1796 {
1797 focused_line2 = -1;
1798 }
1799 else for(size_t line = 0; line < lines.size(); ++line)
1800 {
1801 if(size_t(cursor_start) < lines[line]) //should ALWAYS execute once
1802 {
1803 focused_line2 = line;
1804 break;
1805 }
1806 }
1807 if (focused_line >= lines.size())
1808 focused_line = lines.size() - 1;
1809 if (focused_line2 >= lines.size())
1810 focused_line2 = lines.size() - 1;
1811 if(maxlines >= lines.size() || focused_line <= half_width)
1812 line_scroll = 0;
1813 else if(lines.size()-maxlines+half_width < focused_line)
1814 line_scroll = lines.size()-maxlines+half_width-1;
1815 else
1816 line_scroll = focused_line - half_width;
1817 }
1818 }
1819 font = oldfont; //in case of early return, need to reset here
1820 static bool dclick = false;
1821 switch(msg)
1822 {
1823 case MSG_START:
1824 dclick = false;
1825 cursor_start = (int32_t)strlen((char*)d->dp);
1826 cursor_end = -1;
1827 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
1828 break;
1829
1830 case MSG_DRAW:
1831 {
1832 if(d->dp2)
1833 font = (FONT*)d->dp2;
1834 if(d->flags & D_DISABLED)
1835 {
1836 fg = scheme[jcDISABLED_FG];
1837 bg = scheme[jcDISABLED_BG];
1838 }
1839 else if(d->flags & D_READONLY)
1840 {
1841 fg = scheme[jcALT_TEXTFG];
1842 bg = scheme[jcALT_TEXTBG];
1843 }
1844 else
1845 {
1846 fg = scheme[jcTEXTFG];
1847 bg = scheme[jcTEXTBG];
1848 }
1849
1850 //Fill the BG
1851 rectfill(screen, d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, bg);
1852
1853 //Now the text
1854 size_t m = zc_min(line_scroll + maxlines, lines.size());
1855 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
1856 for(size_t line = line_scroll; line < m; ++line, y+=yinc)
1857 {
1858 x = 3;
1859 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
1860 {
1861 char c = s[ind] ? s[ind] : ' ';
1862 w = char_length(font, c);
1863 bool focused = multiselect
1864 ? (ind >= low_cursor && ind <= high_cursor)
1865 : (ind == cursor_start);
1866 f = (focused && (d->flags & D_GOTFOCUS));
1867 buf[0] = c;
1868 textout_ex(screen, font, buf, d->x+x, y, f ? bg : fg,f ? fg : bg);
1869 x += w;
1870 }
1871 }
1872
1873 font = oldfont;
1874 break;
1875 }
1876
1877 case MSG_DCLICK:
1878 if ((gui_mouse_b() & 2) != 0)
1879 break;
1880 if (d->flags & (D_DISABLED | D_READONLY))
1881 break;
1882 dclick = true;
1883 break;
1884 case MSG_CLICK:
1885 {
1886 if(d->flags & (D_DISABLED|D_READONLY))
1887 break;
1888 if(d->dp2)
1889 font = (FONT*)d->dp2;
1890
1891 bool found = false;
1892 for(size_t line = line_scroll; line < lines.size() && line < (line_scroll + maxlines); ++line, y+=yinc)
1893 {
1894 if(gui_mouse_y() >= y+yinc)
1895 continue;
1896 x = d->x+3;
1897 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
1898 {
1899 x += char_length(font, s[ind]);
1900 if(x >= gui_mouse_x())
1901 {
1902 if(key_shifts&KB_SHIFT_FLAG)
1903 cursor_end = ind;
1904 else
1905 {
1906 cursor_start = ind;
1907 cursor_end = -1;
1908 if (dclick)
1909 cursor_end = cursor_start;
1910 }
1911 found = true;
1912 break;
1913 }
1914 }
1915 break;
1916 }
1917 if(!found)
1918 {
1919 if(key_shifts&KB_SHIFT_FLAG)
1920 cursor_end = l;
1921 else
1922 {
1923 cursor_start = l;
1924 cursor_end = -1;
1925 if (dclick)
1926 cursor_end = cursor_start;
1927 }
1928 }
1929
1930 if (dclick)
1931 {
1932 while (cursor_start > 0 && cursor_start < l)
1933 {
1934 if (s[cursor_start] == ' ')
1935 {
1936 if (cursor_start <= cursor_end)
1937 ++cursor_start;
1938 else
1939 --cursor_start;
1940 break;
1941 }
1942 if (cursor_start <= cursor_end)
1943 --cursor_start;
1944 else
1945 ++cursor_start;
1946 }
1947 while (cursor_end > 0 && cursor_end < l)
1948 {
1949 if (s[cursor_end] == ' ')
1950 {
1951 if (cursor_end >= cursor_start)
1952 --cursor_end;
1953 else
1954 ++cursor_end;
1955 break;
1956 }
1957 if (cursor_end >= cursor_start)
1958 ++cursor_end;
1959 else
1960 --cursor_end;
1961 }
1962 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
1963 d->flags |= D_DIRTY;
1964 }
1965 else
1966 {
1967 if (cursor_end == cursor_start) cursor_end = -1;
1968 else d->flags |= D_DIRTY;
1969 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
1970 }
1971
1972 object_message(d, MSG_DRAW, 0);
1973 font = oldfont;
1974 dclick = false;
1975 break;
1976 }
1977
1978 case MSG_WANTFOCUS:
1979 case MSG_LOSTFOCUS:
1980 case MSG_KEY:
1981 if(d->flags & (D_DISABLED|D_READONLY))
1982 break;
1983 return D_WANTFOCUS;
1984
1985 case MSG_CHAR:
1986 {
1987 if(d->flags & (D_DISABLED|D_READONLY))
1988 break;
1989 bool shifted = key_shifts & KB_SHIFT_FLAG;
1990 bool ctrl = key_shifts & KB_CTRL_FLAG;
1991 bool change_cursor = true;
1992 int32_t scursor = cursor_start, ecursor = cursor_end;
1993 char upper_c = c>>8;
1994 char lower_c = c&255;
1995 if(shifted)
1996 {
1997 if(ecursor < 0)
1998 {
1999 ecursor = scursor;
2000 focused_line2 = focused_line;
2001 }
2002 }
2003 if(upper_c == KEY_LEFT)
2004 {
2005 if(shifted)
2006 {
2007 if(ecursor>0)
2008 --ecursor;
2009 }
2010 else
2011 {
2012 ecursor = -1;
2013 if(scursor > 0)
2014 --scursor;
2015 }
2016 }
2017 else if(upper_c == KEY_RIGHT)
2018 {
2019 if(shifted)
2020 {
2021 if(ecursor < l)
2022 ++ecursor;
2023 }
2024 else
2025 {
2026 ecursor = -1;
2027 if(scursor < l)
2028 ++scursor;
2029 }
2030 }
2031 else if(upper_c == KEY_UP || upper_c == KEY_DOWN)
2032 {
2033 if(shifted)
2034 {
2035 size_t line = focused_line2 + (upper_c == KEY_UP ? -1 : 1);
2036 if(!focused_line2 && upper_c == KEY_UP)
2037 ecursor = 0;
2038 else if(line >= lines.size())
2039 ecursor = l;
2040 else
2041 {
2042 if(d->dp2)
2043 font = (FONT*)d->dp2;
2044 x = d->x + 3;
2045 for(ind = focused_line2 ? lines[focused_line2-1] : 0; ind < lines[focused_line2]; ++ind)
2046 {
2047 w = char_length(font, s[ind]);
2048 if(ind < size_t(ecursor))
2049 x += w;
2050 else
2051 {
2052 x += w / 2;
2053 break;
2054 }
2055 }
2056
2057 int32_t tx = d->x+3;
2058 bool done = false;
2059 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
2060 {
2061 tx += char_length(font, s[ind] ? s[ind] : ' ');
2062 if(tx < x)
2063 continue;
2064 ecursor = ind;
2065 done = true;
2066 break;
2067 }
2068 font = oldfont;
2069 if(!done)
2070 {
2071 ecursor = (upper_c == KEY_UP) ? 0 : lines[line]-1;
2072 }
2073 }
2074 }
2075 else
2076 {
2077 ecursor = -1;
2078 if(multiselect)
2079 {
2080 focused_line = focused_line2;
2081 scursor = ecursor;
2082 }
2083 size_t line = focused_line + (upper_c == KEY_UP ? -1 : 1);
2084 if(!focused_line && upper_c == KEY_UP)
2085 scursor = 0;
2086 else if(line >= lines.size())
2087 scursor = l;
2088 else
2089 {
2090 if(d->dp2)
2091 font = (FONT*)d->dp2;
2092 x = d->x + 3;
2093 for(ind = focused_line ? lines[focused_line-1] : 0; ind < lines[focused_line]; ++ind)
2094 {
2095 w = char_length(font, s[ind]);
2096 if(ind < size_t(scursor))
2097 x += w;
2098 else
2099 {
2100 x += w / 2;
2101 break;
2102 }
2103 }
2104
2105 int32_t tx = d->x+3;
2106 bool done = false;
2107 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
2108 {
2109 tx += char_length(font, s[ind] ? s[ind] : ' ');
2110 if(tx < x)
2111 continue;
2112 scursor = ind;
2113 done = true;
2114 break;
2115 }
2116 font = oldfont;
2117 if(!done)
2118 {
2119 scursor = (upper_c == KEY_UP) ? 0 : lines[line]-1;
2120 }
2121 }
2122 }
2123 }
2124 else if(upper_c == KEY_HOME)
2125 {
2126 if(shifted)
2127 ecursor = 0;
2128 else
2129 {
2130 ecursor = -1;
2131 scursor = 0;
2132 }
2133 }
2134 else if(upper_c == KEY_END)
2135 {
2136 if(shifted)
2137 ecursor = l;
2138 else
2139 {
2140 ecursor = -1;
2141 scursor = l;
2142 }
2143 }
2144 else if(upper_c == KEY_DEL)
2145 {
2146 if(ctrl)
2147 {
2148 s[0] = 0;
2149 scursor = 0;
2150 ecursor = -1;
2151 GUI_EVENT(d, geCHANGE_VALUE);
2152 }
2153 else if(multiselect)
2154 {
2155 ecursor = -1;
2156 scursor = low_cursor;
2157 size_t ind = low_cursor, ind2 = high_cursor+1;
2158 while(s[ind2])
2159 s[ind++] = s[ind2++];
2160 while(s[ind])
2161 s[ind++] = 0;
2162 GUI_EVENT(d, geCHANGE_VALUE);
2163 }
2164 else if(scursor < l)
2165 {
2166 for(p=scursor; s[p]; p++)
2167 s[p] = s[p+1];
2168 GUI_EVENT(d, geCHANGE_VALUE);
2169 }
2170 }
2171 else if(upper_c == KEY_BACKSPACE)
2172 {
2173 if(ctrl)
2174 {
2175 s[0] = 0;
2176 scursor = 0;
2177 ecursor = -1;
2178 GUI_EVENT(d, geCHANGE_VALUE);
2179 }
2180 else if(multiselect)
2181 {
2182 ecursor = -1;
2183 scursor = low_cursor;
2184 size_t ind = low_cursor, ind2 = high_cursor+1;
2185 while(s[ind2])
2186 s[ind++] = s[ind2++];
2187 while(s[ind])
2188 s[ind++] = 0;
2189 GUI_EVENT(d, geCHANGE_VALUE);
2190 }
2191 else if(scursor > 0)
2192 {
2193 --scursor;
2194 for(p=scursor; s[p]; p++)
2195 s[p] = s[p+1];
2196 GUI_EVENT(d, geCHANGE_VALUE);
2197 }
2198 }
2199 else if(upper_c == KEY_ENTER)
2200 {
2201 change_cursor = false;
2202 GUI_EVENT(d, geENTER);
2203 if(d->flags & D_EXIT)
2204 {
2205 object_message(d, MSG_DRAW, 0);
2206 return D_CLOSE;
2207 }
2208 else
2209 return D_O_K;
2210 }
2211 else if(upper_c == KEY_TAB)
2212 {
2213 change_cursor = false;
2214 return D_O_K;
2215 }
2216 else if(ctrl && (lower_c=='c' || lower_c=='C'))
2217 {
2218 change_cursor = false;
2219 std::ostringstream oss;
2220 if(multiselect)
2221 {
2222 for(size_t ind = low_cursor; ind <= high_cursor; ++ind)
2223 {
2224 if(s[ind])
2225 oss << s[ind];
2226 }
2227 }
2228 else
2229 {
2230 if(s[scursor])
2231 oss << s[scursor];
2232 }
2233 set_al_clipboard(oss.str());
2234 }
2235 else if(clipboard_has_text() && ctrl && (lower_c=='v' || lower_c=='V'))
2236 {
2237 std::string cb;
2238 if(get_al_clipboard(cb))
2239 {
2240 int ind = low_cursor, ind2 = high_cursor + 1;
2241 if (multiselect)
2242 {
2243 //Delete selected text
2244 ecursor = -1;
2245 scursor = low_cursor;
2246 while (s[ind2] && ind2 < l)
2247 s[ind++] = s[ind2++];
2248 while (s[ind])
2249 s[ind++] = 0;
2250 l = (int32_t)strlen(s);
2251 }
2252 //Move the text out of the way of the pasting
2253 int paste_len = cb.size();
2254 int paste_start = scursor;
2255 int paste_end = paste_start+paste_len;
2256 ind = strlen(s);
2257 ind2 = ind+paste_len;
2258 while(ind2 > d->d1)
2259 {
2260 --ind;
2261 --ind2;
2262 }
2263 size_t new_l = ind2;
2264 while(ind >= paste_start)
2265 {
2266 if(s[ind] || (ind&&s[ind-1]))
2267 {
2268 s[ind2] = s[ind];
2269 }
2270 --ind2; --ind;
2271 }
2272 for(auto q = 0; q < paste_len && paste_start+q < new_l; ++q)
2273 {
2274 s[paste_start+q] = cb.at(q);
2275 }
2276 s[new_l] = 0;
2277 scursor = paste_start + paste_len;
2278 ecursor = -1;
2279 GUI_EVENT(d, geCHANGE_VALUE);
2280 }
2281 }
2282 else if(ctrl && (lower_c=='a' || lower_c=='A'))
2283 {
2284 cursor_start = 0;
2285 cursor_end = (int16_t)strlen((char*)d->dp) - 1;
2286 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2287 d->flags |= D_DIRTY;
2288 break;
2289 }
2290 else if(lower_c >= 32)
2291 {
2292 if(multiselect)
2293 {
2294 //Delete selected text
2295 ecursor = -1;
2296 scursor = low_cursor;
2297 size_t ind = low_cursor, ind2 = high_cursor+1;
2298 while(s[ind2] && ind2 < l)
2299 s[ind++] = s[ind2++];
2300 while(s[ind])
2301 s[ind++] = 0;
2302 l = (int32_t)strlen(s);
2303 //Type the character in its' place
2304 //(fallthrough)
2305 }
2306 if(l < d->d1)
2307 {
2308 ecursor = -1;
2309 s[l+1] = 0;
2310 size_t ind = l;
2311 while(ind >= scursor)
2312 {
2313 s[ind+1] = s[ind];
2314 if (!ind) break;
2315 --ind;
2316 }
2317
2318 s[scursor++] = lower_c;
2319
2320 GUI_EVENT(d, geCHANGE_VALUE);
2321 }
2322 }
2323 else
2324 return D_O_K;
2325
2326 if(change_cursor)
2327 {
2328 if (cursor_start != scursor)
2329 d->flags |= D_DIRTY;
2330
2331 cursor_end = ecursor; cursor_start = scursor;
2332 if (cursor_end == cursor_start) cursor_end = -1;
2333 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2334 }
2335
2336 /* if we changed something, better redraw... */
2337 object_message(d, MSG_DRAW, 0);
2338 return D_USED_CHAR;
2339 }
2340 }
2341
2342 return D_O_K;
2343 }
2344
2345 /* jwin_edit_proc:
2346 * An editable text object (the dp field points to the string). When it
2347 * has the input focus (obtained by clicking on it with the mouse), text
2348 * can be typed into this object. The d1 field specifies the maximum
2349 * number of characters that it will accept, and d2 is the text cursor
2350 * position within the string.
2351 */
2352 int32_t jwin_edit_proc(int32_t msg, DIALOG *d, int32_t c)
2353 {
2354 if(d->flags & D_HIDDEN)
2355 {
2356 switch(msg)
2357 {
2358 case MSG_CHAR: case MSG_UCHAR: case MSG_XCHAR: case MSG_DRAW: case MSG_CLICK: case MSG_DCLICK: case MSG_KEY: case MSG_WANTFOCUS:
2359 return D_O_K;
2360 }
2361 }
2362 if(d->h >= 2+((text_height(d->dp2 ? (FONT*)d->dp2 : font)+2)*2))
2363 return jwin_vedit_proc(msg, d, c);
2364 int32_t f, l, p, w, x, y, fg, bg, fg2 = -1, bg2 = -1, fg3, bg3;
2365 int32_t b;
2366 int32_t scroll;
2367 char *s;
2368 char buf[2];
2369 static char nullbuf[2];
2370 sprintf(nullbuf, " ");
2371
2372 if(d->dp==NULL)
2373 {
2374 d->dp=(void *)nullbuf;
2375 }
2376
2377 s = (char*)d->dp;
2378 l = (int32_t)strlen(s);
2379
2380 int32_t cursor_start = d->d2 & 0x0000FFFF;
2381 int32_t cursor_end = int32_t((d->d2 & 0xFFFF0000) >> 16);
2382 // This was previously doing bitshifts on -1. There wasn't enough space so I cannibalized 0xFFFF instead. -Moosh
2383 if (cursor_start == 0xFFFF)
2384 cursor_start = -1;
2385 if (cursor_end == 0xFFFF)
2386 cursor_end = -1;
2387
2388 if(cursor_start > l)
2389 cursor_start = l;
2390 if(cursor_end > l)
2391 cursor_end = l;
2392 auto low_cursor = cursor_start<0 ? cursor_end : (cursor_end<0 ? cursor_start : (zc_min(cursor_start, cursor_end)));
2393 auto high_cursor = zc_max(cursor_start,cursor_end);
2394
2395 /* calculate maximal number of displayable characters */
2396 b = x = 0;
2397
2398 if(cursor_start == l)
2399 {
2400 buf[0] = ' ';
2401 buf[1] = 0;
2402
2403 if(d->dp2)
2404 x = text_length((FONT*)d->dp2, buf);
2405 else
2406 x = text_length(font, buf);
2407 }
2408
2409 buf[1] = 0;
2410
2411 for(p=cursor_start; p>=0; p--)
2412 {
2413 buf[0] = s[p];
2414 b++;
2415
2416 if(d->dp2)
2417 x += text_length((FONT*)d->dp2, buf);
2418 else
2419 x += text_length(font, buf);
2420
2421 if(x > d->w-6)
2422 break;
2423 }
2424
2425 if(x <= d->w-6)
2426 {
2427 b = l;
2428 scroll = FALSE;
2429 }
2430 else
2431 {
2432 b--;
2433 scroll = TRUE;
2434 }
2435
2436 FONT *oldfont = font;
2437 static bool dclick = false;
2438 switch(msg)
2439 {
2440 case MSG_START:
2441 dclick = false;
2442 cursor_start = (int32_t)strlen((char*)d->dp);
2443 cursor_end = -1;
2444 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2445 break;
2446
2447 case MSG_DRAW:
2448 {
2449 if(d->dp2)
2450 {
2451 font = (FONT*)d->dp2;
2452 }
2453 if(d->flags & D_DISABLED)
2454 {
2455 fg2 = scheme[jcLIGHT];
2456 bg2 = scheme[jcDISABLED_BG];
2457 fg = scheme[jcDISABLED_FG];
2458 bg = -1;
2459 fg3 = fg;
2460 bg3 = bg2;
2461 }
2462 else if(d->flags & D_READONLY)
2463 {
2464 fg = scheme[jcALT_TEXTFG];
2465 bg = scheme[jcALT_TEXTBG];
2466 fg3 = fg;
2467 bg3 = bg;
2468 }
2469 else
2470 {
2471 fg = scheme[jcTEXTFG];
2472 bg = scheme[jcTEXTBG];
2473 fg3 = fg;
2474 bg3 = bg;
2475 }
2476
2477 x = 3;
2478 y = (d->h - text_height(font)) / 2 + d->y;
2479
2480 /* first fill in the edges */
2481
2482 rectfill(screen, d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, bg3);
2483
2484 vline(screen, d->x+2, d->y+2, d->y+d->h-3, bg3);
2485
2486 /* now the text */
2487
2488 if(scroll)
2489 {
2490 p = cursor_start-b+1;
2491 b = cursor_start;
2492 }
2493 else
2494 p = 0;
2495 for(; p<=b; p++)
2496 {
2497 buf[0] = s[p] ? s[p] : ' ';
2498 w = text_length(font, buf);
2499
2500 if(x+w > d->w)
2501 break;
2502 bool focused = (cursor_end>-1)
2503 ? (p >= low_cursor && p <= high_cursor)
2504 : (p == cursor_start);
2505 f = fg2 < 0 && (focused && (d->flags & D_GOTFOCUS));
2506 if(fg2 > -1)
2507 {
2508 textout_ex(screen, font, buf, d->x+x+1, y+1, fg2, bg2);
2509 }
2510 textout_ex(screen, font, buf, d->x+x, y, f ? bg : fg,f ? fg : bg);
2511 x += w;
2512 }
2513
2514 if(x < d->w-2)
2515 rectfill(screen, d->x+x, y, d->x+d->w-3, y+text_height(font)-1, bg3);
2516
2517 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
2518 font = oldfont;
2519 break;
2520 }
2521
2522 case MSG_DCLICK:
2523 if ((gui_mouse_b() & 2) != 0)
2524 break;
2525 if (d->flags & (D_DISABLED | D_READONLY))
2526 break;
2527 dclick = true;
2528 break;
2529 case MSG_CLICK:
2530 {
2531 if(d->flags & (D_DISABLED|D_READONLY))
2532 break;
2533 x = d->x+3;
2534
2535 if(scroll)
2536 {
2537 p = cursor_start-b+1;
2538 b = cursor_start;
2539 }
2540 else
2541 p = 0;
2542
2543 for(; p<b; p++)
2544 {
2545 buf[0] = s[p];
2546 x += text_length((d->dp2) ? (FONT*)d->dp2 : font, buf);
2547
2548 if(x > gui_mouse_x())
2549 break;
2550 }
2551
2552 if(key_shifts&KB_SHIFT_FLAG)
2553 cursor_end = MID(0, p, l);
2554 else
2555 {
2556 cursor_end = -1;
2557 cursor_start = MID(0, p, l);
2558 if (dclick)
2559 cursor_end = cursor_start;
2560 }
2561
2562 if (dclick)
2563 {
2564 while (cursor_start > 0 && cursor_start < l)
2565 {
2566 if (s[cursor_start] == ' ')
2567 {
2568 if (cursor_start <= cursor_end)
2569 ++cursor_start;
2570 else
2571 --cursor_start;
2572 break;
2573 }
2574 if (cursor_start <= cursor_end)
2575 --cursor_start;
2576 else
2577 ++cursor_start;
2578 }
2579 while (cursor_end > 0 && cursor_end < l)
2580 {
2581 if (s[cursor_end] == ' ')
2582 {
2583 if (cursor_end >= cursor_start)
2584 --cursor_end;
2585 else
2586 ++cursor_end;
2587 break;
2588 }
2589 if (cursor_end >= cursor_start)
2590 ++cursor_end;
2591 else
2592 --cursor_end;
2593 }
2594 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2595 d->flags |= D_DIRTY;
2596 }
2597 else
2598 {
2599 if (cursor_end == cursor_start) cursor_end = -1;
2600 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2601 }
2602 d->flags |= D_DIRTY;
2603 dclick = false;
2604 break;
2605 }
2606
2607 case MSG_WANTFOCUS:
2608 case MSG_LOSTFOCUS:
2609 case MSG_KEY:
2610 if(d->flags & (D_DISABLED|D_READONLY))
2611 break;
2612 return D_WANTFOCUS;
2613
2614 case MSG_CHAR:
2615 {
2616 if(d->flags & (D_DISABLED|D_READONLY))
2617 break;
2618 bool shifted = key_shifts & KB_SHIFT_FLAG;
2619 bool ctrl = key_shifts & KB_CTRL_FLAG;
2620 bool change_cursor = true;
2621 bool change_value = false;
2622 int16_t scursor = cursor_start, ecursor = cursor_end;
2623 bool multiselect = cursor_end > -1;
2624 auto upper_c = c>>8;
2625 auto lower_c = c&0xFF;
2626 if(shifted)
2627 {
2628 if(ecursor < 0)
2629 ecursor = scursor;
2630 }
2631 if(upper_c == KEY_LEFT)
2632 {
2633 if(shifted)
2634 {
2635 if(ecursor>0)
2636 --ecursor;
2637 }
2638 else
2639 {
2640 ecursor = -1;
2641 if(scursor > 0)
2642 --scursor;
2643 }
2644 }
2645 else if(upper_c == KEY_RIGHT)
2646 {
2647 if(shifted)
2648 {
2649 if(ecursor < l)
2650 ++ecursor;
2651 }
2652 else
2653 {
2654 ecursor = -1;
2655 if(scursor < l)
2656 ++scursor;
2657 }
2658 }
2659 else if(upper_c == KEY_HOME)
2660 {
2661 if(shifted)
2662 ecursor = 0;
2663 else
2664 {
2665 ecursor = -1;
2666 scursor = 0;
2667 }
2668 }
2669 else if(upper_c == KEY_END)
2670 {
2671 if(shifted)
2672 ecursor = l;
2673 else
2674 {
2675 ecursor = -1;
2676 scursor = l;
2677 }
2678 }
2679 else if(upper_c == KEY_DEL)
2680 {
2681 if(ctrl)
2682 {
2683 s[0] = 0;
2684 scursor = 0;
2685 ecursor = -1;
2686 GUI_EVENT(d, geCHANGE_VALUE);
2687 change_value = true;
2688 }
2689 else if(multiselect)
2690 {
2691 ecursor = -1;
2692 scursor = low_cursor;
2693 size_t ind = low_cursor, ind2 = high_cursor+1;
2694 while(s[ind2])
2695 s[ind++] = s[ind2++];
2696 while(s[ind])
2697 s[ind++] = 0;
2698 GUI_EVENT(d, geCHANGE_VALUE);
2699 change_value = true;
2700 }
2701 else if(scursor < l)
2702 {
2703 for(p=scursor; s[p]; p++)
2704 s[p] = s[p+1];
2705 GUI_EVENT(d, geCHANGE_VALUE);
2706 change_value = true;
2707 }
2708 }
2709 else if(upper_c == KEY_BACKSPACE)
2710 {
2711 if(ctrl)
2712 {
2713 s[0] = 0;
2714 scursor = 0;
2715 ecursor = -1;
2716 GUI_EVENT(d, geCHANGE_VALUE);
2717 change_value = true;
2718 }
2719 else if(multiselect)
2720 {
2721 ecursor = -1;
2722 scursor = low_cursor;
2723 size_t ind = low_cursor, ind2 = high_cursor+1;
2724 while(s[ind2])
2725 s[ind++] = s[ind2++];
2726 while(s[ind])
2727 s[ind++] = 0;
2728 GUI_EVENT(d, geCHANGE_VALUE);
2729 change_value = true;
2730 }
2731 else if(scursor > 0)
2732 {
2733 --scursor;
2734 for(p=scursor; s[p]; p++)
2735 s[p] = s[p+1];
2736 GUI_EVENT(d, geCHANGE_VALUE);
2737 change_value = true;
2738 }
2739 }
2740 else if(upper_c == KEY_ENTER)
2741 {
2742 change_cursor = false;
2743 GUI_EVENT(d, geENTER);
2744 if(d->flags & D_EXIT)
2745 {
2746 object_message(d, MSG_DRAW, 0);
2747 return D_CLOSE;
2748 }
2749 else
2750 return D_O_K;
2751 }
2752 else if(upper_c == KEY_TAB)
2753 {
2754 change_cursor = false;
2755 return D_O_K;
2756 }
2757 else if(ctrl && (lower_c=='c' || lower_c=='C'))
2758 {
2759 change_cursor = false;
2760 std::ostringstream oss;
2761 if(multiselect)
2762 {
2763 for(size_t ind = low_cursor; ind <= high_cursor; ++ind)
2764 {
2765 if(s[ind])
2766 oss << s[ind];
2767 }
2768 }
2769 else
2770 {
2771 if(s[scursor])
2772 oss << s[scursor];
2773 }
2774 set_al_clipboard(oss.str());
2775 }
2776 else if(clipboard_has_text() && ctrl && (lower_c=='v' || lower_c=='V'))
2777 {
2778 std::string cb;
2779 if(get_al_clipboard(cb))
2780 {
2781 int ind = low_cursor, ind2 = high_cursor + 1;
2782 if (multiselect)
2783 {
2784 //Delete selected text
2785 ecursor = -1;
2786 scursor = low_cursor;
2787 while (s[ind2] && ind2 < l)
2788 s[ind++] = s[ind2++];
2789 while (s[ind])
2790 s[ind++] = 0;
2791 l = (int32_t)strlen(s);
2792 }
2793 //Move the text out of the way of the pasting
2794 int paste_len = cb.size();
2795 int paste_start = scursor;
2796 int paste_end = paste_start+paste_len;
2797 ind = strlen(s);
2798 ind2 = ind+paste_len;
2799 while(ind2 > d->d1)
2800 {
2801 --ind;
2802 --ind2;
2803 }
2804 size_t new_l = ind2;
2805 while(ind >= paste_start)
2806 {
2807 if(s[ind] || (ind&&s[ind-1]))
2808 {
2809 s[ind2] = s[ind];
2810 }
2811 --ind2; --ind;
2812 }
2813 for(auto q = 0; q < paste_len && paste_start+q < new_l; ++q)
2814 {
2815 s[paste_start+q] = cb.at(q);
2816 }
2817 s[new_l] = 0;
2818 scursor = paste_start + paste_len;
2819 ecursor = -1;
2820 GUI_EVENT(d, geCHANGE_VALUE);
2821 change_value = true;
2822 }
2823 }
2824 else if(ctrl && (lower_c=='a' || lower_c=='A'))
2825 {
2826 cursor_start = 0;
2827 cursor_end = (int16_t)strlen((char*)d->dp) - 1;
2828 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2829 d->flags |= D_DIRTY;
2830 break;
2831 }
2832 else if(lower_c >= 32)
2833 {
2834 if(multiselect)
2835 {
2836 //Delete selected text
2837 ecursor = -1;
2838 scursor = low_cursor;
2839 size_t ind = low_cursor, ind2 = high_cursor+1;
2840 while(s[ind2] && ind2 < l)
2841 s[ind++] = s[ind2++];
2842 while(s[ind])
2843 s[ind++] = 0;
2844 l = (int32_t)strlen(s);
2845 //Type the character in its' place
2846 //(fallthrough)
2847 }
2848 if(l < d->d1)
2849 {
2850 ecursor = -1;
2851 s[l+1] = 0;
2852 size_t ind = l;
2853 while(ind >= scursor)
2854 {
2855 s[ind+1] = s[ind];
2856 if (!ind) break;
2857 --ind;
2858 }
2859
2860 s[scursor++] = lower_c;
2861
2862 GUI_EVENT(d, geCHANGE_VALUE);
2863 change_value = true;
2864 }
2865 }
2866 else
2867 return D_O_K;
2868 if(change_cursor)
2869 {
2870 cursor_end = ecursor; cursor_start = scursor;
2871 if (cursor_end == cursor_start) cursor_end = -1;
2872 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2873 }
2874 /* if we changed something, better redraw... */
2875 // Note: this still redraws when not necessary.
2876 if (change_value || change_cursor)
2877 d->flags |= D_DIRTY;
2878 return D_USED_CHAR;
2879 }
2880 }
2881 return D_O_K;
2882 }
2883
2884 int32_t jwin_hexedit_proc_old(int32_t msg,DIALOG *d,int32_t c)
2885 {
2886 if(msg==MSG_CHAR)
2887 if(((isalpha(c&255) && !isxdigit(c&255))) || ispunct(c&255))
2888 return D_USED_CHAR;
2889
2890 return jwin_edit_proc(msg,d,isalpha(c&255)?c&0xDF:c);
2891 }
2892
2893 bool editproc_special_key(int32_t c)
2894 {
2895 switch(c>>8)
2896 {
2897 case KEY_LEFT: case KEY_RIGHT:
2898 case KEY_HOME: case KEY_END:
2899 case KEY_DEL: case KEY_BACKSPACE:
2900 case KEY_ENTER: case KEY_TAB:
2901 return true;
2902 }
2903 if(key_shifts & KB_CTRL_FLAG)
2904 switch(c&255)
2905 {
2906 case 'c': case 'C':
2907 return true;
2908 case 'v': case 'V':
2909 return clipboard_has_text();
2910 }
2911 return false;
2912 }
2913 bool editproc_combined_key(int32_t c)
2914 {
2915 if(key_shifts & KB_CTRL_FLAG)
2916 switch(c&255)
2917 {
2918 case 'c': case 'C':
2919 return true;
2920 case 'v': case 'V':
2921 return clipboard_has_text();
2922 }
2923 return false;
2924 }
2925 int32_t jwin_hexedit_proc(int32_t msg,DIALOG *d,int32_t c)
2926 {
2927 bool caps_paste = false;
2928 if(msg==MSG_CHAR)
2929 {
2930 if(key_shifts & KB_CTRL_FLAG)
2931 {
2932 if(clipboard_has_text() && ((c&255)=='v' || (c&255)=='V'))
2933 {
2934 std::string cb;
2935 if(get_al_clipboard(cb))
2936 {
2937 if(cb.find_first_not_of("-.0123456789ABCDEFabcdef") != std::string::npos)
2938 return D_USED_CHAR;
2939 if(cb.find_first_of("abcdef") != std::string::npos)
2940 caps_paste = true;
2941 }
2942 else return D_USED_CHAR;
2943 }
2944 }
2945 switch(c&255)
2946 {
2947 case '-': case '.':
2948 case '0': case '1': case '2': case '3': case '4':
2949 case '5': case '6': case '7': case '8': case '9':
2950 case 'A': case 'B': case 'C':
2951 case 'D': case 'E': case 'F':
2952 break;
2953 case 'a': case 'b': case 'c':
2954 case 'd': case 'e': case 'f':
2955 c = (c&~255)|toupper(c&255);
2956 break;
2957 default:
2958 if(!editproc_special_key(c))
2959 return D_O_K;
2960 else if(!editproc_combined_key(c))
2961 c&=~255;
2962 }
2963 }
2964
2965 auto ret = jwin_edit_proc(msg,d,c);
2966 if(caps_paste)
2967 {
2968 char* s = (char*)d->dp;
2969 caps_paste = false;
2970 for(int q = strlen(s)-1; q >= 0; --q)
2971 {
2972 switch(s[q])
2973 {
2974 case 'a': case 'b': case 'c':
2975 case 'd': case 'e': case 'f':
2976 s[q] = toupper(s[q]);
2977 caps_paste = true;
2978 break;
2979 }
2980 }
2981 if(caps_paste)
2982 {
2983 jwin_edit_proc(MSG_DRAW,d,0);
2984 }
2985 }
2986 return ret;
2987 }
2988 int32_t jwin_numedit_proc(int32_t msg,DIALOG *d,int32_t c)
2989 {
2990 if(msg==MSG_CHAR)
2991 {
2992 if(key_shifts & KB_CTRL_FLAG)
2993 {
2994 if(clipboard_has_text() && ((c&255)=='v' || (c&255)=='V'))
2995 {
2996 std::string cb;
2997 if(get_al_clipboard(cb))
2998 {
2999 if(cb.find_first_not_of("-.0123456789") != std::string::npos)
3000 return D_USED_CHAR;
3001 }
3002 else return D_USED_CHAR;
3003 }
3004 }
3005 switch(c&255)
3006 {
3007 case '-': case '.':
3008 case '0': case '1': case '2': case '3': case '4':
3009 case '5': case '6': case '7': case '8': case '9':
3010 break;
3011 default:
3012 if(!editproc_special_key(c))
3013 return D_O_K;
3014 else if(!editproc_combined_key(c))
3015 c&=~255;
3016 }
3017 }
3018
3019 return jwin_edit_proc(msg,d,c);
3020 }
3021
3022 int32_t jwin_numedit_byte_proc(int32_t msg,DIALOG *d,int32_t c)
3023 {
3024 if ( (atoi((char*)d->dp)) > 255 )
3025 {
3026 strcpy((char*)d->dp,"255\0");
3027 return jwin_numedit_proc(msg,d,c);
3028 }
3029 else if ( (atoi((char*)d->dp)) < 0 )
3030 {
3031 strcpy((char*)d->dp,"0\0");
3032 return jwin_numedit_proc(msg,d,c);
3033 }
3034
3035 return jwin_numedit_proc(msg,d,c);
3036 }
3037
3038 int32_t jwin_numedit_short_proc(int32_t msg,DIALOG *d,int32_t c)
3039 {
3040 if ( (atoi((char*)d->dp)) > 65535 )
3041 {
3042 strcpy((char*)d->dp,"65535\0");
3043 return jwin_numedit_proc(msg,d,c);
3044 }
3045 else if ( (atoi((char*)d->dp)) < 0 )
3046 {
3047 strcpy((char*)d->dp,"0\0");
3048 return jwin_numedit_proc(msg,d,c);
3049 }
3050
3051 return jwin_numedit_proc(msg,d,c);
3052 }
3053
3054 int32_t jwin_numedit_zscriptint_proc(int32_t msg,DIALOG *d,int32_t c)
3055 {
3056 if ( (atoi((char*)d->dp)) > 214748 )
3057 {
3058 strcpy((char*)d->dp,"214748\0");
3059 return jwin_numedit_proc(msg,d,c);
3060 }
3061 else if ( (atoi((char*)d->dp)) < -214748 )
3062 {
3063 strcpy((char*)d->dp,"-214748\0");
3064 return jwin_numedit_proc(msg,d,c);
3065 }
3066
3067 return jwin_numedit_proc(msg,d,c);
3068 }
3069
3070 int32_t jwin_numedit_sshort_proc(int32_t msg,DIALOG *d,int32_t c)
3071 {
3072 if ( (atoi((char*)d->dp)) > 32767 )
3073 {
3074 strcpy((char*)d->dp,"32767\0");
3075 return jwin_numedit_proc(msg,d,c);
3076 }
3077 else if ( (atoi((char*)d->dp)) < -32768 )
3078 {
3079 strcpy((char*)d->dp,"-32768\0");
3080 return jwin_numedit_proc(msg,d,c);
3081 }
3082
3083 return jwin_numedit_proc(msg,d,c);
3084 }
3085
3086 int32_t jwin_numedit_sbyte_proc(int32_t msg,DIALOG *d,int32_t c)
3087 {
3088 if ( (atoi((char*)d->dp)) > 127 )
3089 {
3090 strcpy((char*)d->dp,"127\0");
3091 return jwin_numedit_proc(msg,d,c);
3092 }
3093 else if ( (atoi((char*)d->dp)) < -128 )
3094 {
3095 strcpy((char*)d->dp,"-128\0");
3096 return jwin_numedit_proc(msg,d,c);
3097 }
3098
3099 return jwin_numedit_proc(msg,d,c);
3100 }
3101
3102 // Special numedit procs
3103
3104 void trim_trailing_0s(char* str, bool leaveDec = false)
3105 {
3106 bool foundDec = false;
3107 for(int32_t q = 0; str[q]; ++q)
3108 {
3109 if(str[q] == '.')
3110 {
3111 foundDec = true;
3112 break;
3113 }
3114 }
3115 if(!foundDec) return; //No decimal place, thus no trailing 0's.
3116 for(int32_t q = strlen(str)-1; q > 0; --q)
3117 {
3118 if(str[q] == '0' && (!leaveDec || str[q-1] != '.'))
3119 {
3120 str[q] = 0;
3121 }
3122 else if(str[q] == '.')
3123 {
3124 str[q] = 0;
3125 return;
3126 }
3127 else return;
3128 }
3129 }
3130 int32_t jwin_swapbtn_proc(int32_t msg, DIALOG* d, int32_t c)
3131 {
3132 static const char* swp[nswapMAX] = {"D", "H", "LD", "LH", "B"};
3133 d->dp = (void*)swp[d->d1&0xF];
3134 //d1 is (0xF0 = old val, 0x0F = new val)
3135 //d2 is max val
3136 if(d->d2 < 2 || d->d2 > nswapMAX) return D_O_K; //Not setup yet, or bad value
3137 DIALOG* relproc = (DIALOG*)d->dp3;
3138 GUI::TextField *tf_obj = nullptr;
3139 if(d->d2 > nswapBOOL) tf_obj = (GUI::TextField*)relproc->dp3;
3140 int32_t ret = jwin_button_proc(msg, d, c);
3141 if(d->flags & D_SELECTED) //On selection
3142 {
3143 d->d1 = ((d->d1&0x0F)<<4) | (((d->d1&0x0F)+1)%d->d2);
3144 d->dp = (void*)swp[d->d1&0xF];
3145 d->flags &= ~D_SELECTED;
3146 if(tf_obj) tf_obj->refresh_cb_swap();
3147 if(relproc)
3148 {
3149 object_message(relproc, MSG_DRAW, 0);
3150 }
3151 object_message(d, MSG_DRAW, 0);
3152 }
3153 return ret;
3154 }
3155 int32_t jwin_numedit_swap_byte_proc(int32_t msg, DIALOG *d, int32_t c)
3156 {
3157 DIALOG* swapbtn;
3158 if(d->flags&D_NEW_GUI)
3159 {
3160 swapbtn = d+1;
3161 }
3162 else swapbtn = (DIALOG*)d->dp3;
3163 if(!swapbtn) return D_O_K;
3164 if(msg==MSG_START) //Setup the swapbtn
3165 {
3166 d->bg = 0;
3167 swapbtn->d2 = 2; //Max states
3168 auto ty = swapbtn->d1&0xF;
3169 if(unsigned(ty) > swapbtn->d2)
3170 swapbtn->d1 &= ~0xF;
3171 swapbtn->dp3 = (void*)d;
3172 }
3173 int32_t ret = D_O_K;
3174 int32_t ntype = swapbtn->d1&0xF,
3175 otype = swapbtn->d1>>4;
3176
3177 char* str = (char*)d->dp;
3178 int32_t v = 0;
3179 if(msg == MSG_START)
3180 v = d->fg;
3181 else switch(otype)
3182 {
3183 case nswapDEC:
3184 v = atoi(str);
3185 break;
3186 case nswapHEX:
3187 v = zc_xtoi(str);
3188 break;
3189 }
3190 byte b;
3191 if ( v > 255 )
3192 b=255;
3193 else if ( v < 0 )
3194 b=0;
3195 else b = (byte)v;
3196 if(msg==MSG_CHAR && ((c&255)=='-'))
3197 {
3198 //unsigned//b = -b;
3199 c &= ~255;
3200 }
3201 if(unsigned(v) != b || otype != ntype || msg == MSG_START)
3202 {
3203 switch(ntype)
3204 {
3205 case nswapDEC:
3206 sprintf(str, "%d", b);
3207 break;
3208 case nswapHEX:
3209 sprintf(str, "%X", b);
3210 break;
3211 }
3212 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3213 }
3214
3215 if(d->fg != b)
3216 {
3217 d->fg = b; //Store numeric data
3218 GUI_EVENT(d, geUPDATE_SWAP);
3219 }
3220 switch(ntype)
3221 {
3222 case nswapDEC:
3223 d->d1 = 3; //3 digits max
3224 ret |= jwin_numedit_proc(msg, d, c);
3225 break;
3226 case nswapHEX:
3227 d->d1 = 2; //2 digits max
3228 if(msg == MSG_CHAR && isalpha(c&255)) //always capitalize
3229 c = (c&~255) | (toupper(c&255));
3230 ret |= jwin_hexedit_proc(msg, d, c);
3231 break;
3232 }
3233
3234 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3235
3236 return ret;
3237 }
3238 #define INC_TF_CURSORS(val,inc,max) \
3239 do \
3240 { \
3241 int32_t scursor = (val & 0xFFFF)+inc; \
3242 int32_t ecursor = (val & 0xFFFF0000) >> 16; \
3243 bool valid_ecursor = ecursor != 0xFFFF; \
3244 if(valid_ecursor) ecursor += inc; \
3245 if(inc < 0) \
3246 { \
3247 if(scursor < 0) scursor = 0; \
3248 if(valid_ecursor && ecursor < 0) ecursor = 0; \
3249 } \
3250 else \
3251 { \
3252 if(scursor > max) scursor = max; \
3253 if(valid_ecursor && ecursor > max) ecursor = max; \
3254 } \
3255 val = scursor | (ecursor<<16); \
3256 } while(false)
3257 int32_t jwin_numedit_swap_sshort_proc(int32_t msg, DIALOG *d, int32_t c)
3258 {
3259 const size_t maxlen = 7;
3260 DIALOG* swapbtn;
3261 if(d->flags&D_NEW_GUI)
3262 {
3263 swapbtn = d+1;
3264 }
3265 else swapbtn = (DIALOG*)d->dp3;
3266 if(!swapbtn) return D_O_K;
3267 if(msg==MSG_START) //Setup the swapbtn
3268 {
3269 d->bg = 0;
3270 swapbtn->d2 = 2; //Max states
3271 auto ty = swapbtn->d1&0xF;
3272 if(unsigned(ty) > swapbtn->d2)
3273 swapbtn->d1 &= ~0xF;
3274 swapbtn->dp3 = (void*)d;
3275 }
3276 int32_t ret = D_O_K;
3277 int32_t ntype = swapbtn->d1&0xF,
3278 otype = swapbtn->d1>>4;
3279
3280 char* str = (char*)d->dp;
3281 int32_t v = 0;
3282 if(msg == MSG_START)
3283 v = d->fg;
3284 else switch(otype)
3285 {
3286 case nswapDEC:
3287 v = atoi(str);
3288 break;
3289 case nswapHEX:
3290 v = zc_xtoi(str);
3291 break;
3292 }
3293 int16_t b;
3294 if ( v > 32767 )
3295 b=32767;
3296 else if ( v < -32768 )
3297 b=-32768;
3298 else b = (int16_t)v;
3299 bool queued_neg = d->bg;
3300 if(msg==MSG_CHAR && ((c&255)=='-'))
3301 {
3302 if(b)
3303 {
3304 b = -b;
3305 v = b;
3306 if(b<0)
3307 {
3308 if(str[0] != '-')
3309 {
3310 char buf[16] = {0};
3311 strcpy(buf, str);
3312 sprintf(str, "-%s", buf);
3313 INC_TF_CURSORS(d->d2,1,strlen(str));
3314 }
3315 }
3316 else if(str[0] == '-')
3317 {
3318 char buf[16] = {0};
3319 strcpy(buf, str);
3320 sprintf(str, "%s", buf+1);
3321 INC_TF_CURSORS(d->d2,-1,strlen(str));
3322 }
3323 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3324 }
3325 else queued_neg = !queued_neg; //queue the negative
3326 c &= ~255;
3327 ret |= D_USED_CHAR;
3328 }
3329 if(b && queued_neg)
3330 {
3331 //b = -b; //actually, 'atoi' handles it for us.....
3332 queued_neg = false;
3333 }
3334 if(bool(d->bg) != queued_neg)
3335 {
3336 d->bg = queued_neg;
3337 if(queued_neg)
3338 {
3339 if(str[0] != '-')
3340 {
3341 char buf[16] = {0};
3342 strcpy(buf, str);
3343 sprintf(str, "-%s", buf);
3344 INC_TF_CURSORS(d->d2,1,strlen(str));
3345 }
3346 }
3347 else if(!b && str[0] == '-')
3348 {
3349 char buf[16] = {0};
3350 strcpy(buf, str);
3351 sprintf(str, "%s", buf+1);
3352 INC_TF_CURSORS(d->d2,-1,strlen(str));
3353 }
3354 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3355 }
3356 if(v != b || otype != ntype || msg == MSG_START)
3357 {
3358 switch(ntype)
3359 {
3360 case nswapDEC:
3361 sprintf(str, "%d", b);
3362 break;
3363 case nswapHEX:
3364 if(b<0)
3365 sprintf(str, "-%X", -b);
3366 else sprintf(str, "%X", b);
3367 break;
3368 }
3369 d->d2 = 0xFFFF0000|strlen(str);
3370 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3371 }
3372
3373 if(d->fg != b)
3374 {
3375 d->fg = b; //Store numeric data
3376 GUI_EVENT(d, geUPDATE_SWAP);
3377 }
3378 bool rev_d2 = false;
3379 int32_t old_d2 = d->d2;
3380 int32_t ref_d2;
3381 if(msg == MSG_CHAR && queued_neg)
3382 {
3383 auto scursor = d->d2 & 0xFFFF;
3384 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3385 if(!scursor)
3386 {
3387 rev_d2 = true;
3388 INC_TF_CURSORS(d->d2,1,strlen(str));
3389 ref_d2 = d->d2;
3390 }
3391 }
3392 switch(ntype)
3393 {
3394 case nswapDEC:
3395 d->d1 = 6; //6 digits max (incl '-')
3396 ret |= jwin_numedit_proc(msg, d, c);
3397 break;
3398 case nswapHEX:
3399 d->d1 = 5; //5 digits max (incl '-')
3400 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
3401 c = (c&~255) | (toupper(c&255));
3402 ret |= jwin_hexedit_proc(msg, d, c);
3403 break;
3404 }
3405 if(rev_d2 && ref_d2 == d->d2)
3406 {
3407 d->d2 = old_d2;
3408 }
3409
3410 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3411
3412 return ret;
3413 }
3414 int32_t jwin_numedit_swap_zsint_proc(int32_t msg, DIALOG *d, int32_t c)
3415 {
3416 const size_t maxlen = 13;
3417 DIALOG* swapbtn;
3418 if(d->flags&D_NEW_GUI)
3419 {
3420 swapbtn = d+1;
3421 }
3422 else swapbtn = (DIALOG*)d->dp3;
3423 if(!swapbtn) return D_O_K;
3424 if(msg==MSG_START) //Setup the swapbtn
3425 {
3426 d->bg = 0;
3427 swapbtn->d2 = 4; //Max states
3428 auto ty = swapbtn->d1&0xF;
3429 if(unsigned(ty) > swapbtn->d2)
3430 swapbtn->d1 &= ~0xF;
3431 swapbtn->dp3 = (void*)d;
3432 }
3433 int32_t ret = D_O_K;
3434 int32_t ntype = swapbtn->d1&0xF,
3435 otype = swapbtn->d1>>4;
3436
3437 char* str = (char*)d->dp;
3438 int64_t v = 0;
3439 if(msg == MSG_START)
3440 v = d->fg;
3441 else switch(otype)
3442 {
3443 case nswapDEC:
3444 if(char *ptr = strchr(str, '.'))
3445 {
3446 char tempstr[32] = {0};
3447 strcpy(tempstr, str);
3448 for(int32_t q = 0; q < 4; ++q)
3449 tempstr[strlen(str)+q]='0';
3450 ptr = strchr(tempstr, '.');
3451 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3452 v = atoi(tempstr);
3453 v *= 10000;
3454 if(tempstr[0] == '-')
3455 v -= atoi(ptr);
3456 else v += atoi(ptr);
3457 }
3458 else
3459 {
3460 v = atoi(str);
3461 v *= 10000;
3462 }
3463 break;
3464 case nswapHEX:
3465 if(char *ptr = strchr(str, '.'))
3466 {
3467 char tempstr[32] = {0};
3468 strcpy(tempstr, str);
3469 for(int32_t q = 0; q < 4; ++q)
3470 tempstr[strlen(str)+q]='0';
3471 ptr = strchr(tempstr, '.');
3472 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3473 v = zc_xtoi(tempstr);
3474 v *= 10000;
3475 if(tempstr[0] == '-')
3476 v -= atoi(ptr);
3477 else v += atoi(ptr);
3478 }
3479 else
3480 {
3481 v = zc_xtoi(str);
3482 v *= 10000;
3483 }
3484 break;
3485 case nswapLDEC:
3486 v = zc_atoi64(str);
3487 break;
3488 case nswapLHEX:
3489 v = zc_xtoi64(str);
3490 break;
3491 }
3492 int32_t b;
3493 if ( v > 2147483647 )
3494 b=2147483647;
3495 else if ( v < INT_MIN )
3496 b=INT_MIN;
3497 else b = (int32_t)v;
3498 bool queued_neg = d->bg;
3499 if(msg==MSG_CHAR && ((c&255)=='-'))
3500 {
3501 if(b)
3502 {
3503 if(b==INT_MIN)
3504 ++b;
3505 b = -b;
3506 v = b;
3507 if(b<0)
3508 {
3509 if(str[0] != '-')
3510 {
3511 char buf[16] = {0};
3512 strcpy(buf, str);
3513 sprintf(str, "-%s", buf);
3514 INC_TF_CURSORS(d->d2,1,strlen(str));
3515 }
3516 }
3517 else if(str[0] == '-')
3518 {
3519 char buf[16] = {0};
3520 strcpy(buf, str);
3521 sprintf(str, "%s", buf+1);
3522 INC_TF_CURSORS(d->d2,-1,strlen(str));
3523 }
3524 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3525 }
3526 else queued_neg = !queued_neg; //queue negative
3527 c &= ~255;
3528 ret |= D_USED_CHAR;
3529 }
3530 if(b && queued_neg)
3531 {
3532 //b = -b; //actually, 'atoi' handles it for us.....
3533 queued_neg = false;
3534 }
3535 if(bool(d->bg) != queued_neg)
3536 {
3537 d->bg = queued_neg;
3538 if(queued_neg)
3539 {
3540 if(str[0] != '-')
3541 {
3542 char buf[16] = {0};
3543 strcpy(buf, str);
3544 sprintf(str, "-%s", buf);
3545 INC_TF_CURSORS(d->d2,1,strlen(str));
3546 }
3547 }
3548 else if(!b && str[0] == '-')
3549 {
3550 char buf[16] = {0};
3551 strcpy(buf, str);
3552 sprintf(str, "%s", buf+1);
3553 INC_TF_CURSORS(d->d2,-1,strlen(str));
3554 }
3555 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3556 }
3557 if(v != b || otype != ntype || msg == MSG_START)
3558 {
3559 switch(ntype)
3560 {
3561 case nswapDEC:
3562 if(b < 0)
3563 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
3564 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
3565 trim_trailing_0s(str);
3566 break;
3567 case nswapHEX:
3568 if(b<0)
3569 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
3570 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
3571 trim_trailing_0s(str);
3572 break;
3573 case nswapLDEC:
3574 sprintf(str, "%d", b);
3575 break;
3576 case nswapLHEX:
3577 if(b<0)
3578 sprintf(str, "-%X", -b);
3579 else sprintf(str, "%X", b);
3580 break;
3581 }
3582 d->d2 = 0xFFFF0000|strlen(str);
3583 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3584 }
3585 if(d->fg != b)
3586 {
3587 d->fg = b; //Store numeric data
3588 GUI_EVENT(d, geUPDATE_SWAP);
3589 }
3590 if(msg==MSG_CHAR && ((c&255)=='.'))
3591 {
3592 if(ntype >= nswapLDEC) //No '.' in long modes
3593 c&=~255;
3594 else
3595 {
3596 for(int32_t q = 0; str[q]; ++q)
3597 {
3598 if(str[q] == '.') //Only one '.'
3599 {
3600 c&=~255;
3601 break;
3602 }
3603 }
3604 }
3605 }
3606 bool rev_d2 = false;
3607 int32_t old_d2 = d->d2;
3608 int32_t ref_d2;
3609 if(msg == MSG_CHAR && queued_neg)
3610 {
3611 auto scursor = d->d2 & 0xFFFF;
3612 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3613 if(!scursor)
3614 {
3615 rev_d2 = true;
3616 INC_TF_CURSORS(d->d2,1,strlen(str));
3617 ref_d2 = d->d2;
3618 }
3619 }
3620 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
3621 switch(ntype)
3622 {
3623 case nswapDEC:
3624 d->d1 = 12; //12 digits max (incl '-', '.')
3625 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
3626 {
3627 int32_t p = 0;
3628 for(int32_t q = 0; str[q]; ++q)
3629 {
3630 if(str[q]=='.')
3631 {
3632 if((d->d2&0x0000FFFF) <= q)
3633 break; //typing before the '.'
3634 ++p;
3635 }
3636 else if(p) ++p;
3637 }
3638 if(p>=5) //too many chars after '.'
3639 c&=~255;
3640 }
3641 ret |= jwin_numedit_proc(msg, d, c);
3642 break;
3643 case nswapHEX:
3644 d->d1 = 11; //11 digits max (incl '-', '.')
3645 if(msg==MSG_CHAR && !editproc_special_key(c))
3646 {
3647 if(!((c&255)=='.'||isxdigit(c&255)))
3648 c&=~255;
3649 else if(isxdigit(c&255) && !isdigit(c&255))
3650 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
3651 {
3652 if(str[q] == '.') //No hex digits to the right of the '.'
3653 {
3654 c&=~255;
3655 break;
3656 }
3657 }
3658 if((c&255) && !areaselect)
3659 {
3660 int32_t p = 0;
3661 for(int32_t q = 0; str[q]; ++q)
3662 {
3663 if(str[q]=='.')
3664 {
3665 if((d->d2&0x0000FFFF) <= q)
3666 break; //typing before the '.'
3667 ++p;
3668 }
3669 else if(p) ++p;
3670 }
3671 if(p>=5) //too many chars after '.'
3672 c&=~255;
3673 }
3674 if(isalpha(c&255)) //always capitalize
3675 c = (c&~255) | (toupper(c&255));
3676 }
3677 ret |= jwin_hexedit_proc(msg, d, c);
3678 break;
3679 case nswapLDEC:
3680 d->d1 = 11; //11 digits max (incl '-')
3681 ret |= jwin_numedit_proc(msg, d, c);
3682 break;
3683 case nswapLHEX:
3684 d->d1 = 9; //9 digits max (incl '-')
3685 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
3686 c = (c&~255) | (toupper(c&255));
3687 ret |= jwin_hexedit_proc(msg, d, c);
3688 break;
3689 }
3690 if(rev_d2 && ref_d2 == d->d2)
3691 {
3692 d->d2 = old_d2;
3693 }
3694
3695 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3696
3697 return ret;
3698 }
3699 int32_t jwin_numedit_swap_zsint_nodec_proc(int32_t msg, DIALOG *d, int32_t c)
3700 {
3701 const size_t maxlen = 7;
3702 DIALOG* swapbtn;
3703 if(d->flags&D_NEW_GUI)
3704 {
3705 swapbtn = d+1;
3706 }
3707 else swapbtn = (DIALOG*)d->dp3;
3708 if(!swapbtn) return D_O_K;
3709 if(msg==MSG_START) //Setup the swapbtn
3710 {
3711 d->bg = 0;
3712 swapbtn->d2 = 2; //Max states
3713 auto ty = swapbtn->d1&0xF;
3714 if(unsigned(ty) > swapbtn->d2)
3715 swapbtn->d1 &= ~0xF;
3716 swapbtn->dp3 = (void*)d;
3717 }
3718 int32_t ret = D_O_K;
3719 int32_t ntype = swapbtn->d1&0xF,
3720 otype = swapbtn->d1>>4;
3721
3722 char* str = (char*)d->dp;
3723 int64_t v = 0;
3724 if(msg == MSG_START)
3725 v = d->fg;
3726 else switch(otype)
3727 {
3728 case nswapDEC:
3729 v = atoi(str);
3730 v *= 10000;
3731 break;
3732 case nswapHEX:
3733 v = zc_xtoi(str);
3734 v *= 10000;
3735 break;
3736 }
3737 int32_t b;
3738 if ( v > 2147480000 )
3739 b=2147480000;
3740 else if ( v < -2147480000 )
3741 b=-2147480000;
3742 else b = (int32_t)v;
3743 bool queued_neg = d->bg;
3744 if(msg==MSG_CHAR && ((c&255)=='-'))
3745 {
3746 if(b)
3747 {
3748 if(b==INT_MIN)
3749 ++b;
3750 b = -b;
3751 v = b;
3752 if(b<0)
3753 {
3754 if(str[0] != '-')
3755 {
3756 char buf[16] = {0};
3757 strcpy(buf, str);
3758 sprintf(str, "-%s", buf);
3759 INC_TF_CURSORS(d->d2,1,strlen(str));
3760 }
3761 }
3762 else if(str[0] == '-')
3763 {
3764 char buf[16] = {0};
3765 strcpy(buf, str);
3766 sprintf(str, "%s", buf+1);
3767 INC_TF_CURSORS(d->d2,-1,strlen(str));
3768 }
3769 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3770 }
3771 else queued_neg = !queued_neg; //queue negative
3772 c &= ~255;
3773 ret |= D_USED_CHAR;
3774 }
3775 if(b && queued_neg)
3776 {
3777 //b = -b; //actually, 'atoi' handles it for us.....
3778 queued_neg = false;
3779 }
3780 if(bool(d->bg) != queued_neg)
3781 {
3782 d->bg = queued_neg;
3783 if(queued_neg)
3784 {
3785 if(str[0] != '-')
3786 {
3787 char buf[16] = {0};
3788 strcpy(buf, str);
3789 sprintf(str, "-%s", buf);
3790 INC_TF_CURSORS(d->d2,1,strlen(str));
3791 }
3792 }
3793 else if(!b && str[0] == '-')
3794 {
3795 char buf[16] = {0};
3796 strcpy(buf, str);
3797 sprintf(str, "%s", buf+1);
3798 INC_TF_CURSORS(d->d2,-1,strlen(str));
3799 }
3800 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3801 }
3802 if(v != b || otype != ntype || msg == MSG_START)
3803 {
3804 switch(ntype)
3805 {
3806 case nswapDEC:
3807 if(b < 0)
3808 sprintf(str, "-%ld", abs(b/10000L));
3809 else sprintf(str, "%ld", b/10000L);
3810 break;
3811 case nswapHEX:
3812 if(b<0)
3813 sprintf(str, "-%lX", abs(b/10000L));
3814 else sprintf(str, "%lX", b/10000L);
3815 break;
3816 }
3817 d->d2 = 0xFFFF0000|strlen(str);
3818 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3819 }
3820 if(d->fg != b)
3821 {
3822 d->fg = b; //Store numeric data
3823 GUI_EVENT(d, geUPDATE_SWAP);
3824 }
3825 if(msg==MSG_CHAR && ((c&255)=='.'))
3826 {
3827 c&=~255; //no '.' in nodec version
3828 }
3829 bool rev_d2 = false;
3830 int32_t old_d2 = d->d2;
3831 int32_t ref_d2;
3832 if(msg == MSG_CHAR && queued_neg)
3833 {
3834 auto scursor = d->d2 & 0xFFFF;
3835 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3836 if(!scursor)
3837 {
3838 rev_d2 = true;
3839 INC_TF_CURSORS(d->d2,1,strlen(str));
3840 ref_d2 = d->d2;
3841 }
3842 }
3843 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
3844 switch(ntype)
3845 {
3846 case nswapDEC:
3847 d->d1 = 7; //7 digits max (incl '-')
3848 ret |= jwin_numedit_proc(msg, d, c);
3849 break;
3850 case nswapHEX:
3851 d->d1 = 6; //6 digits max (incl '-')
3852 if(msg==MSG_CHAR && !editproc_special_key(c))
3853 {
3854 if(!isxdigit(c&255))
3855 c&=~255;
3856 if(isalpha(c&255)) //always capitalize
3857 c = (c&~255) | (toupper(c&255));
3858 }
3859 ret |= jwin_hexedit_proc(msg, d, c);
3860 break;
3861 }
3862 if(rev_d2 && ref_d2 == d->d2)
3863 {
3864 d->d2 = old_d2;
3865 }
3866
3867 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3868
3869 return ret;
3870 }
3871 int32_t jwin_numedit_swap_zsint2_proc(int32_t msg, DIALOG *d, int32_t c)
3872 {
3873 const size_t maxlen = 13;
3874 DIALOG* swapbtn;
3875 ASSERT(d->flags&D_NEW_GUI);
3876 swapbtn = d+1;
3877 if(!swapbtn) return D_O_K;
3878 GUI::TextField *tf_obj = (GUI::TextField*)d->dp3;
3879 if(!tf_obj) return D_O_K;
3880 if(msg==MSG_START) //Setup the swapbtn
3881 {
3882 d->bg = 0;
3883 swapbtn->d2 = 5; //Max states
3884 auto ty = swapbtn->d1&0xF;
3885 if(unsigned(ty) > swapbtn->d2)
3886 swapbtn->d1 &= ~0xF;
3887 swapbtn->dp3 = (void*)d;
3888 }
3889 int32_t ret = D_O_K;
3890 int32_t ntype = swapbtn->d1&0xF,
3891 otype = swapbtn->d1>>4;
3892 if(otype==nswapBOOL || ntype == nswapBOOL)
3893 {
3894 if(otype != ntype)
3895 {
3896 tf_obj->refresh_cb_swap();
3897 }
3898 if(ntype == nswapBOOL)
3899 {
3900 swapbtn->d1 = (ntype<<4)|ntype;
3901 return D_O_K;
3902 }
3903 }
3904
3905 char* str = (char*)d->dp;
3906 int64_t v = 0;
3907 if(msg == MSG_START)
3908 v = d->fg;
3909 else switch(otype)
3910 {
3911 case nswapDEC:
3912 if(char *ptr = strchr(str, '.'))
3913 {
3914 char tempstr[32] = {0};
3915 strcpy(tempstr, str);
3916 for(int32_t q = 0; q < 4; ++q)
3917 tempstr[strlen(str)+q]='0';
3918 ptr = strchr(tempstr, '.');
3919 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3920 v = atoi(tempstr);
3921 v *= 10000;
3922 if(tempstr[0] == '-')
3923 v -= atoi(ptr);
3924 else v += atoi(ptr);
3925 }
3926 else
3927 {
3928 v = atoi(str);
3929 v *= 10000;
3930 }
3931 break;
3932 case nswapHEX:
3933 if(char *ptr = strchr(str, '.'))
3934 {
3935 char tempstr[32] = {0};
3936 strcpy(tempstr, str);
3937 for(int32_t q = 0; q < 4; ++q)
3938 tempstr[strlen(str)+q]='0';
3939 ptr = strchr(tempstr, '.');
3940 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3941 v = zc_xtoi(tempstr);
3942 v *= 10000;
3943 if(tempstr[0] == '-')
3944 v -= atoi(ptr);
3945 else v += atoi(ptr);
3946 }
3947 else
3948 {
3949 v = zc_xtoi(str);
3950 v *= 10000;
3951 }
3952 break;
3953 case nswapLDEC:
3954 v = zc_atoi64(str);
3955 break;
3956 case nswapLHEX:
3957 v = zc_xtoi64(str);
3958 break;
3959 case nswapBOOL:
3960 v = d->fg;
3961 break;
3962 }
3963 int32_t b;
3964 if ( v > 2147483647 )
3965 b=2147483647;
3966 else if ( v < INT_MIN )
3967 b=INT_MIN;
3968 else b = (int32_t)v;
3969 bool queued_neg = d->bg;
3970 if(msg==MSG_CHAR && ((c&255)=='-'))
3971 {
3972 if(b)
3973 {
3974 if(b==INT_MIN)
3975 ++b;
3976 b = -b;
3977 v = b;
3978 if(b<0)
3979 {
3980 if(str[0] != '-')
3981 {
3982 char buf[16] = {0};
3983 strcpy(buf, str);
3984 sprintf(str, "-%s", buf);
3985 INC_TF_CURSORS(d->d2,1,strlen(str));
3986 }
3987 }
3988 else if(str[0] == '-')
3989 {
3990 char buf[16] = {0};
3991 strcpy(buf, str);
3992 sprintf(str, "%s", buf+1);
3993 INC_TF_CURSORS(d->d2,-1,strlen(str));
3994 }
3995 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3996 }
3997 else queued_neg = !queued_neg; //queue negative
3998 c &= ~255;
3999 ret |= D_USED_CHAR;
4000 }
4001 if(b && queued_neg)
4002 {
4003 //b = -b; //actually, 'atoi' handles it for us.....
4004 queued_neg = false;
4005 }
4006 if(bool(d->bg) != queued_neg)
4007 {
4008 d->bg = queued_neg;
4009 if(queued_neg)
4010 {
4011 if(str[0] != '-')
4012 {
4013 char buf[16] = {0};
4014 strcpy(buf, str);
4015 sprintf(str, "-%s", buf);
4016 INC_TF_CURSORS(d->d2,1,strlen(str));
4017 }
4018 }
4019 else if(!b && str[0] == '-')
4020 {
4021 char buf[16] = {0};
4022 strcpy(buf, str);
4023 sprintf(str, "%s", buf+1);
4024 INC_TF_CURSORS(d->d2,-1,strlen(str));
4025 }
4026 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4027 }
4028 if(v != b || otype != ntype || msg == MSG_START)
4029 {
4030 switch(ntype)
4031 {
4032 case nswapDEC:
4033 if(b < 0)
4034 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
4035 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
4036 trim_trailing_0s(str);
4037 break;
4038 case nswapHEX:
4039 if(b<0)
4040 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
4041 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
4042 trim_trailing_0s(str);
4043 break;
4044 case nswapLDEC:
4045 sprintf(str, "%d", b);
4046 break;
4047 case nswapLHEX:
4048 if(b<0)
4049 sprintf(str, "-%X", -b);
4050 else sprintf(str, "%X", b);
4051 break;
4052 }
4053 d->d2 = 0xFFFF0000|strlen(str);
4054 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4055 }
4056 if(d->fg != b)
4057 {
4058 d->fg = b; //Store numeric data
4059 GUI_EVENT(d, geUPDATE_SWAP);
4060 }
4061 if(msg==MSG_CHAR && ((c&255)=='.'))
4062 {
4063 if(ntype >= nswapLDEC) //No '.' in long modes
4064 c&=~255;
4065 else
4066 {
4067 for(int32_t q = 0; str[q]; ++q)
4068 {
4069 if(str[q] == '.') //Only one '.'
4070 {
4071 c&=~255;
4072 break;
4073 }
4074 }
4075 }
4076 }
4077 bool rev_d2 = false;
4078 int32_t old_d2 = d->d2;
4079 int32_t ref_d2;
4080 if(msg == MSG_CHAR && queued_neg)
4081 {
4082 auto scursor = d->d2 & 0xFFFF;
4083 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
4084 if(!scursor)
4085 {
4086 rev_d2 = true;
4087 INC_TF_CURSORS(d->d2,1,strlen(str));
4088 ref_d2 = d->d2;
4089 }
4090 }
4091 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
4092 switch(ntype)
4093 {
4094 case nswapDEC:
4095 d->d1 = 12; //12 digits max (incl '-', '.')
4096 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
4097 {
4098 int32_t p = 0;
4099 for(int32_t q = 0; str[q]; ++q)
4100 {
4101 if(str[q]=='.')
4102 {
4103 if((d->d2&0x0000FFFF) <= q)
4104 break; //typing before the '.'
4105 ++p;
4106 }
4107 else if(p) ++p;
4108 }
4109 if(p>=5) //too many chars after '.'
4110 c&=~255;
4111 }
4112 ret |= jwin_numedit_proc(msg, d, c);
4113 break;
4114 case nswapHEX:
4115 d->d1 = 11; //11 digits max (incl '-', '.')
4116 if(msg==MSG_CHAR && !editproc_special_key(c))
4117 {
4118 if(!((c&255)=='.'||isxdigit(c&255)))
4119 c&=~255;
4120 else if(isxdigit(c&255) && !isdigit(c&255))
4121 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
4122 {
4123 if(str[q] == '.') //No hex digits to the right of the '.'
4124 {
4125 c&=~255;
4126 break;
4127 }
4128 }
4129 if((c&255) && !areaselect)
4130 {
4131 int32_t p = 0;
4132 for(int32_t q = 0; str[q]; ++q)
4133 {
4134 if(str[q]=='.')
4135 {
4136 if((d->d2&0x0000FFFF) <= q)
4137 break; //typing before the '.'
4138 ++p;
4139 }
4140 else if(p) ++p;
4141 }
4142 if(p>=5) //too many chars after '.'
4143 c&=~255;
4144 }
4145 if(isalpha(c&255)) //always capitalize
4146 c = (c&~255) | (toupper(c&255));
4147 }
4148 ret |= jwin_hexedit_proc(msg, d, c);
4149 break;
4150 case nswapLDEC:
4151 d->d1 = 11; //11 digits max (incl '-')
4152 ret |= jwin_numedit_proc(msg, d, c);
4153 break;
4154 case nswapLHEX:
4155 d->d1 = 9; //9 digits max (incl '-')
4156 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
4157 c = (c&~255) | (toupper(c&255));
4158 ret |= jwin_hexedit_proc(msg, d, c);
4159 break;
4160 }
4161 if(rev_d2 && ref_d2 == d->d2)
4162 {
4163 d->d2 = old_d2;
4164 }
4165
4166 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
4167
4168 if(msg==MSG_START)
4169 tf_obj->refresh_cb_swap();
4170
4171 return ret;
4172 }
4173 int32_t jwin_numedit_noswap_zsint_proc(int32_t msg, DIALOG *d, int32_t c)
4174 {
4175 const size_t maxlen = 13;
4176 ASSERT(d->flags&D_NEW_GUI);
4177 GUI::TextField *tf_obj = (GUI::TextField*)d->dp3;
4178 if(!tf_obj) return D_O_K;
4179 int32_t ret = D_O_K;
4180 int32_t type = tf_obj->getSwapType();
4181
4182 char* str = (char*)d->dp;
4183 int64_t v = 0;
4184 if(msg == MSG_START)
4185 v = d->fg;
4186 else switch(type)
4187 {
4188 case nswapDEC:
4189 if(char *ptr = strchr(str, '.'))
4190 {
4191 char tempstr[32] = {0};
4192 strcpy(tempstr, str);
4193 for(int32_t q = 0; q < 4; ++q)
4194 tempstr[strlen(str)+q]='0';
4195 ptr = strchr(tempstr, '.');
4196 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4197 v = atoi(tempstr);
4198 v *= 10000;
4199 if(tempstr[0] == '-')
4200 v -= atoi(ptr);
4201 else v += atoi(ptr);
4202 }
4203 else
4204 {
4205 v = atoi(str);
4206 v *= 10000;
4207 }
4208 break;
4209 case nswapHEX:
4210 if(char *ptr = strchr(str, '.'))
4211 {
4212 char tempstr[32] = {0};
4213 strcpy(tempstr, str);
4214 for(int32_t q = 0; q < 4; ++q)
4215 tempstr[strlen(str)+q]='0';
4216 ptr = strchr(tempstr, '.');
4217 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4218 v = zc_xtoi(tempstr);
4219 v *= 10000;
4220 if(tempstr[0] == '-')
4221 v -= atoi(ptr);
4222 else v += atoi(ptr);
4223 }
4224 else
4225 {
4226 v = zc_xtoi(str);
4227 v *= 10000;
4228 }
4229 break;
4230 case nswapLDEC:
4231 v = zc_atoi64(str);
4232 break;
4233 case nswapLHEX:
4234 v = zc_xtoi64(str);
4235 break;
4236 case nswapBOOL:
4237 v = d->fg;
4238 break;
4239 }
4240 int32_t b;
4241 if ( v > 2147483647 )
4242 b=2147483647;
4243 else if ( v < INT_MIN )
4244 b=INT_MIN;
4245 else b = (int32_t)v;
4246 bool queued_neg = d->bg;
4247 if(msg==MSG_CHAR && ((c&255)=='-'))
4248 {
4249 if(b)
4250 {
4251 if(b==INT_MIN)
4252 ++b;
4253 b = -b;
4254 v = b;
4255 if(b<0)
4256 {
4257 if(str[0] != '-')
4258 {
4259 char buf[16] = {0};
4260 strcpy(buf, str);
4261 sprintf(str, "-%s", buf);
4262 INC_TF_CURSORS(d->d2,1,strlen(str));
4263 }
4264 }
4265 else if(str[0] == '-')
4266 {
4267 char buf[16] = {0};
4268 strcpy(buf, str);
4269 sprintf(str, "%s", buf+1);
4270 INC_TF_CURSORS(d->d2,-1,strlen(str));
4271 }
4272 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4273 }
4274 else queued_neg = !queued_neg; //queue negative
4275 c &= ~255;
4276 ret |= D_USED_CHAR;
4277 }
4278 if(b && queued_neg)
4279 {
4280 //b = -b; //actually, 'atoi' handles it for us.....
4281 queued_neg = false;
4282 }
4283 if(bool(d->bg) != queued_neg)
4284 {
4285 d->bg = queued_neg;
4286 if(queued_neg)
4287 {
4288 if(str[0] != '-')
4289 {
4290 char buf[16] = {0};
4291 strcpy(buf, str);
4292 sprintf(str, "-%s", buf);
4293 INC_TF_CURSORS(d->d2,1,strlen(str));
4294 }
4295 }
4296 else if(!b && str[0] == '-')
4297 {
4298 char buf[16] = {0};
4299 strcpy(buf, str);
4300 sprintf(str, "%s", buf+1);
4301 INC_TF_CURSORS(d->d2,-1,strlen(str));
4302 }
4303 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4304 }
4305 if(v != b || msg == MSG_START)
4306 {
4307 switch(type)
4308 {
4309 case nswapDEC:
4310 if(b < 0)
4311 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
4312 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
4313 trim_trailing_0s(str);
4314 break;
4315 case nswapHEX:
4316 if(b<0)
4317 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
4318 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
4319 trim_trailing_0s(str);
4320 break;
4321 case nswapLDEC:
4322 sprintf(str, "%d", b);
4323 break;
4324 case nswapLHEX:
4325 if(b<0)
4326 sprintf(str, "-%X", -b);
4327 else sprintf(str, "%X", b);
4328 break;
4329 }
4330 d->d2 = 0xFFFF0000|strlen(str);
4331 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4332 }
4333 if(d->fg != b)
4334 {
4335 d->fg = b; //Store numeric data
4336 GUI_EVENT(d, geUPDATE_SWAP);
4337 }
4338 if(msg==MSG_CHAR && ((c&255)=='.'))
4339 {
4340 if(type >= nswapLDEC) //No '.' in long modes
4341 c&=~255;
4342 else
4343 {
4344 for(int32_t q = 0; str[q]; ++q)
4345 {
4346 if(str[q] == '.') //Only one '.'
4347 {
4348 c&=~255;
4349 break;
4350 }
4351 }
4352 }
4353 }
4354 bool rev_d2 = false;
4355 int32_t old_d2 = d->d2;
4356 int32_t ref_d2;
4357 if(msg == MSG_CHAR && queued_neg)
4358 {
4359 auto scursor = d->d2 & 0xFFFF;
4360 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
4361 if(!scursor)
4362 {
4363 rev_d2 = true;
4364 INC_TF_CURSORS(d->d2,1,strlen(str));
4365 ref_d2 = d->d2;
4366 }
4367 }
4368 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
4369 switch(type)
4370 {
4371 case nswapDEC:
4372 d->d1 = 12; //12 digits max (incl '-', '.')
4373 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
4374 {
4375 int32_t p = 0;
4376 for(int32_t q = 0; str[q]; ++q)
4377 {
4378 if(str[q]=='.')
4379 {
4380 if((d->d2&0x0000FFFF) <= q)
4381 break; //typing before the '.'
4382 ++p;
4383 }
4384 else if(p) ++p;
4385 }
4386 if(p>=5) //too many chars after '.'
4387 c&=~255;
4388 }
4389 ret |= jwin_numedit_proc(msg, d, c);
4390 break;
4391 case nswapHEX:
4392 d->d1 = 11; //11 digits max (incl '-', '.')
4393 if(msg==MSG_CHAR && !editproc_special_key(c))
4394 {
4395 if(!((c&255)=='.'||isxdigit(c&255)))
4396 c&=~255;
4397 else if(isxdigit(c&255) && !isdigit(c&255))
4398 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
4399 {
4400 if(str[q] == '.') //No hex digits to the right of the '.'
4401 {
4402 c&=~255;
4403 break;
4404 }
4405 }
4406 if((c&255) && !areaselect)
4407 {
4408 int32_t p = 0;
4409 for(int32_t q = 0; str[q]; ++q)
4410 {
4411 if(str[q]=='.')
4412 {
4413 if((d->d2&0x0000FFFF) <= q)
4414 break; //typing before the '.'
4415 ++p;
4416 }
4417 else if(p) ++p;
4418 }
4419 if(p>=5) //too many chars after '.'
4420 c&=~255;
4421 }
4422 if(isalpha(c&255)) //always capitalize
4423 c = (c&~255) | (toupper(c&255));
4424 }
4425 ret |= jwin_hexedit_proc(msg, d, c);
4426 break;
4427 case nswapLDEC:
4428 d->d1 = 11; //11 digits max (incl '-')
4429 ret |= jwin_numedit_proc(msg, d, c);
4430 break;
4431 case nswapLHEX:
4432 d->d1 = 9; //9 digits max (incl '-')
4433 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
4434 c = (c&~255) | (toupper(c&255));
4435 ret |= jwin_hexedit_proc(msg, d, c);
4436 break;
4437 }
4438 if(rev_d2 && ref_d2 == d->d2)
4439 {
4440 d->d2 = old_d2;
4441 }
4442
4443 if(msg==MSG_START)
4444 tf_obj->refresh_cb_swap();
4445
4446 return ret;
4447 }
4448
4449 /* _calc_scroll_bar:
4450 * Helps find positions of buttons on the scroll bar.
4451 */
4452 void _calc_scroll_bar(int32_t h, int32_t height, int32_t listsize, int32_t offset,
4453 int32_t *bh, int32_t *len, int32_t *pos)
4454 {
4455 *bh = zc_max(zc_min((h-4)/2, 14), 0);
4456 *len = zc_max(((h - 32) * height + listsize/2) / listsize , 6);
4457 *pos = ((h - 32 - *len) * offset) / (listsize-height);
4458 }
4459
4460 /* _handle_scrollable_click:
4461 * Helper to process a click on a scrollable object.
4462 */
4463
4464 void _handle_jwin_scrollable_scroll_click(DIALOG *d, int32_t listsize, int32_t *offset, FONT *fnt)
4465 {
4466 enum { top_btn, bottom_btn, bar, top_bar, bottom_bar };
4467
4468 int32_t xx, yy;
4469 int32_t height = (d->h-3) / (fnt ? text_height(fnt) : 1);
4470 int32_t hh = d->h - 32;
4471 int32_t obj = bar;
4472 int32_t bh, len, pos;
4473 int32_t down = 1, last_draw = 0;
4474 int32_t redraw = 0, mouse_delay = 0;
4475
4476 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4477
4478 xx = d->x + d->w - 18;
4479
4480 // find out which object is being clicked
4481
4482 yy = gui_mouse_y();
4483
4484 if(yy <= d->y+2+bh)
4485 {
4486 obj = top_btn;
4487 yy = d->y+2;
4488 }
4489 else if(yy >= d->y+d->h-2-bh)
4490 {
4491 obj = bottom_btn;
4492 yy = d->y+d->h-2-bh;
4493 }
4494 else if(d->h > 32+6)
4495 {
4496 if(yy < d->y+2+bh+pos)
4497 obj = top_bar;
4498 else if(yy >= d->y+2+bh+pos+len)
4499 obj = bottom_bar;
4500 }
4501
4502 while(gui_mouse_b())
4503 {
4504 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4505
4506 switch(obj)
4507 {
4508 case top_btn:
4509 case bottom_btn:
4510 down = mouse_in_rect(xx, yy, 16, bh);
4511
4512 if(!down)
4513 mouse_delay = 0;
4514 else
4515 {
4516 if((mouse_delay&1)==0)
4517 {
4518 if(obj==top_btn && *offset>0)
4519 {
4520 (*offset)--;
4521 redraw = 1;
4522 }
4523
4524 if(obj==bottom_btn && *offset<listsize-height)
4525 {
4526 (*offset)++;
4527 redraw = 1;
4528 }
4529 }
4530
4531 mouse_delay++;
4532 }
4533
4534 if(down!=last_draw || redraw)
4535 {
4536 vsync();
4537 d->proc(MSG_DRAW, d, 0);
4538 draw_arrow_button(screen, xx, yy, 16, bh, obj==top_btn, down*3);
4539 last_draw = down;
4540 }
4541
4542 break;
4543
4544 case top_bar:
4545 case bottom_bar:
4546 if(mouse_in_rect(xx, d->y+2, 16, d->h-4))
4547 {
4548 if(obj==top_bar)
4549 {
4550 if(gui_mouse_y() < d->y+2+bh+pos)
4551 yy = *offset - height;
4552 }
4553 else
4554 {
4555 if(gui_mouse_y() >= d->y+2+bh+pos+len)
4556 yy = *offset + height;
4557 }
4558
4559 if(yy < 0)
4560 yy = 0;
4561
4562 if(yy > listsize-height)
4563 yy = listsize-height;
4564
4565 if(yy != *offset)
4566 {
4567 *offset = yy;
4568 vsync();
4569 d->proc(MSG_DRAW, d, 0);
4570 }
4571 }
4572
4573 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4574
4575 if(!mouse_in_rect(xx, d->y+2+bh+pos, 16, len))
4576 break;
4577
4578 // fall through
4579
4580 case bar:
4581 default:
4582 xx = gui_mouse_y() - pos;
4583
4584 while(gui_mouse_b())
4585 {
4586 yy = (listsize * (gui_mouse_y() - xx) + hh/2) / hh;
4587
4588 if(yy > listsize-height)
4589 yy = listsize-height;
4590
4591 if(yy < 0)
4592 yy = 0;
4593
4594 bool should_redraw = false;
4595 if(yy != *offset)
4596 {
4597 *offset = yy;
4598 d->proc(MSG_DRAW, d, 0);
4599 should_redraw = true;
4600 }
4601
4602 /* let other objects continue to animate */
4603 int r = broadcast_dialog_message(MSG_IDLE, 0);
4604 if (r & D_REDRAWME) should_redraw = true;
4605
4606 if (should_redraw)
4607 {
4608 update_hw_screen();
4609 }
4610 }
4611
4612 break;
4613
4614 } // switch(obj)
4615
4616 redraw = 0;
4617
4618 update_hw_screen();
4619 // let other objects continue to animate
4620 broadcast_dialog_message(MSG_IDLE, 0);
4621 }
4622
4623 if(last_draw==1)
4624 {
4625 draw_arrow_button(screen, xx, yy, 16, bh, obj==top_btn, 0);
4626 }
4627 }
4628
4629 /* _handle_scrollable_scroll:
4630 * Helper function to scroll through a scrollable object.
4631 */
4632
4633 static void _handle_jwin_scrollable_scroll(DIALOG *d, int32_t listsize, int32_t *index, int32_t *offset, FONT *fnt)
4634 {
4635 int32_t height = (d->h-3) / text_height(fnt);
4636
4637 if(listsize <= 0)
4638 {
4639 *index = *offset = 0;
4640 return;
4641 }
4642
4643 // check selected item
4644 if(*index < 0)
4645 *index = 0;
4646 else if(*index >= listsize)
4647 *index = listsize - 1;
4648
4649 // check scroll position
4650 while((*offset > 0) && (*offset + height > listsize))
4651 (*offset)--;
4652
4653 if(*offset >= *index)
4654 {
4655 if(*index < 0)
4656 *offset = 0;
4657 else
4658 *offset = *index;
4659 }
4660 else
4661 {
4662 while((*offset + height - 1) < *index)
4663 (*offset)++;
4664 }
4665 }
4666
4667 /* idle_cb:
4668 * rest_callback() routine to keep dialogs animating nice and smoothly.
4669 */
4670
4671 static void idle_cb()
4672 {
4673 broadcast_dialog_message(MSG_IDLE, 0);
4674 }
4675
4676 /* _handle_listbox_click:
4677 * Helper to process a click on a listbox, doing hit-testing and moving
4678 * the selection.
4679 */
4680
4681 static bool _handle_jwin_listbox_click(DIALOG *d)
4682 {
4683 ListData *data = (ListData *)d->dp;
4684 char *sel = (char *)d->dp2;
4685 int32_t listsize, height;
4686 int32_t i, j;
4687
4688 data->listFunc(-1, &listsize);
4689
4690 if(!listsize)
4691 return false;
4692
4693 height = (d->h-3) / text_height(*data->font);
4694
4695 i = MID(0, ((gui_mouse_y() - d->y - 4) / text_height(*data->font)),
4696 ((d->h-3) / text_height(*data->font) - 1));
4697 i += d->d2;
4698
4699 if(i < d->d2)
4700 i = d->d2;
4701 else
4702 {
4703 if(i > d->d2 + height-1)
4704 i = d->d2 + height-1;
4705
4706 if(i >= listsize)
4707 i = listsize-1;
4708 }
4709
4710 if(gui_mouse_y() <= d->y)
4711 i = MAX(i-1, 0);
4712 else if(gui_mouse_y() >= d->y+d->h)
4713 i = MIN(i+1, listsize-1);
4714
4715 if(i != d->d1)
4716 {
4717 if(sel)
4718 {
4719 if(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG))
4720 {
4721 if((key_shifts & KB_SHIFT_FLAG) || (d->flags & D_INTERNAL))
4722 {
4723 for(j=MIN(i, d->d1); j<=MAX(i, d->d1); j++)
4724 sel[j] = TRUE;
4725 }
4726 else
4727 sel[i] = TRUE;
4728 }
4729 }
4730
4731 d->d1 = i;
4732 i = d->d2;
4733
4734 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
4735
4736 object_message(d, MSG_DRAW, 0);
4737
4738 if(i != d->d2)
4739 rest_callback(MID(10, text_height(font)*16-d->h, 100), idle_cb);
4740 return true;
4741 }
4742 return false;
4743 }
4744
4745 /* _jwin_draw_scrollable_frame:
4746 * Helper function to draw a frame for all objects with vertical scrollbars.
4747 */
4748 void _jwin_draw_scrollable_frame(DIALOG *d, int32_t listsize, int32_t offset, int32_t height, int32_t type)
4749 {
4750 int32_t pos, len;
4751 int32_t xx, yy, hh, bh;
4752 static BITMAP *pattern = NULL; // just create it once
4753
4754 /* draw frame */
4755 if(type)
4756 // for droplists
4757 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DARK);
4758 else
4759 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
4760
4761 /* possibly draw scrollbar */
4762 if(listsize > height)
4763 {
4764 _calc_scroll_bar(d->h, height, listsize, offset, &bh, &len, &pos);
4765
4766 xx = d->x + d->w - 18;
4767
4768 draw_arrow_button(screen, xx, d->y+2, 16, bh, 1, 0);
4769 draw_arrow_button(screen, xx, d->y+d->h-2-bh, 16, bh, 0, 0);
4770
4771 if(d->h > 32)
4772 {
4773 yy = d->y + 16;
4774 hh = (d->h-32);
4775
4776 /* create and draw the scrollbar */
4777 if(!pattern)
4778 pattern = create_bitmap_ex(bitmap_color_depth(screen),2,2);
4779
4780 putpixel(pattern, 0, 1, scheme[jcLIGHT]);
4781 putpixel(pattern, 1, 0, scheme[jcLIGHT]);
4782 putpixel(pattern, 0, 0, scheme[jcBOX]);
4783 putpixel(pattern, 1, 1, scheme[jcBOX]);
4784
4785 drawing_mode(DRAW_MODE_COPY_PATTERN, pattern, 0, 0);
4786 rectfill(screen, xx, yy, xx+15, yy+hh-1, 0);
4787 solid_mode();
4788
4789 if(d->h > 32+6)
4790 {
4791 jwin_draw_button(screen, xx, yy+pos, 16, len, 0, 1);
4792 }
4793 }
4794
4795 if(d->flags & D_GOTFOCUS)
4796 _dotted_rect(d->x+2, d->y+2, d->x+d->w-19, d->y+d->h-3, scheme[jcTEXTFG], scheme[jcTEXTBG]);
4797 }
4798 else if(d->flags & D_GOTFOCUS)
4799 _dotted_rect(d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, scheme[jcTEXTFG], scheme[jcTEXTBG]);
4800 }
4801
4802 /*
4803 Effectively an overload of _jwin_draw_listbox that is used eclusively for file/abc listers.
4804 */
4805 void _jwin_draw_abclistbox(DIALOG *d)
4806 {
4807 int32_t height, listsize, i, len, bar, x, y, w;
4808 int32_t fg_color, bg_color, fg, bg;
4809 char *sel = (char*)d->dp2;
4810 char s[1024] = { 0 };
4811 ListData *data = (ListData *)d->dp;
4812
4813 FONT* oldfont = font;
4814 font = *data->font;
4815
4816 data->listFunc(-1, &listsize);
4817 height = (d->h-3) / text_height(font);
4818 bar = (listsize > height);
4819 w = (bar ? d->w-21 : d->w-5);
4820 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h+9, scheme[jcBOX]);
4821 fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : (d->fg ? d->fg : scheme[jcTEXTFG]);
4822 bg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_BG] : (d->bg ? d->bg : scheme[jcTEXTBG]);
4823
4824 rectfill(screen, d->x+2, d->y+2, d->x+w+2, d->y+3, bg_color);
4825 vline(screen, d->x+2, d->y+4, d->y+d->h-3, bg_color);
4826 vline(screen, d->x+3, d->y+4, d->y+d->h-3, bg_color);
4827 vline(screen, d->x+w+1, d->y+4, d->y+d->h-3, bg_color);
4828 vline(screen, d->x+w+2, d->y+4, d->y+d->h-3, bg_color);
4829 {
4830 rectfill(screen, d->x+1, d->y+d->h+2, d->x+d->w-2, d->y+1+d->h+text_height(font), bg_color);
4831 strncpy(s, abc_keypresses, 1023);
4832 char* s2 = s;
4833 int32_t tw = (d->w-1);
4834 while(text_length(font, s2) >= tw)
4835 {
4836 ++s2;
4837 }
4838 textout_ex(screen, font, s2, d->x+1, d->y+d->h+2,fg_color, bg_color);
4839 }
4840 //d->flags|=D_DIRTY;
4841
4842 /* draw box contents */
4843 for(i=0; i<height; i++)
4844 {
4845 if(d->d2+i < listsize)
4846 {
4847 if(d->d2+i == d->d1 && !(d->flags & D_DISABLED))
4848 {
4849 fg = scheme[jcSELFG];
4850 bg = scheme[jcSELBG];
4851 }
4852 else if((sel) && (sel[d->d2+i]))
4853 {
4854 fg = scheme[jcDISABLED_FG];
4855 bg = scheme[jcSELBG];
4856 }
4857 else
4858 {
4859 fg = fg_color;
4860 bg = bg_color;
4861 }
4862
4863 strncpy(s, data->listFunc(i+d->d2, NULL), 1023);
4864 x = d->x + 4;
4865 y = d->y + 4 + i*text_height(*data->font);
4866 // text_mode(bg);
4867 rectfill(screen, x, y, x+7, y+text_height(*data->font)-1, bg);
4868 x += 8;
4869 len = (int32_t)strlen(s);
4870
4871 while(text_length(*data->font, s) >= d->w - (bar ? 26 : 10))
4872 {
4873 len--;
4874 s[len] = 0;
4875 }
4876
4877 textout_ex(screen, *data->font, s, x, y, fg,bg);
4878 x += text_length(*data->font, s);
4879
4880 if(x <= d->x+w)
4881 rectfill(screen, x, y, d->x+w, y+text_height(*data->font)-1, bg);
4882 }
4883 else
4884 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4885 d->x+w+2, d->y+3+(i+1)*text_height(*data->font), bg_color);
4886 }
4887
4888 if(d->y+4+i*text_height(font) <= d->y+d->h-3)
4889 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4890 d->x+w+2, d->y+d->h-3, bg_color);
4891
4892 /* draw frame, maybe with scrollbar */
4893 _jwin_draw_scrollable_frame(d, listsize, d->d2, height, (d->flags&D_USER)?1:0);
4894
4895 font = oldfont;
4896 }
4897
4898 /* _jwin_draw_listbox:
4899 * Helper function to draw a listbox object.
4900 */
4901 void _jwin_draw_listbox(DIALOG *d)
4902 {
4903 int32_t height, listsize, i, len, bar, x, y, w;
4904 int32_t fg_color, bg_color, fg, bg;
4905 char *sel = (char*)d->dp2;
4906 char s[1024] = {0};
4907 ListData *data = (ListData *)d->dp;
4908
4909 data->listFunc(-1, &listsize);
4910 height = (d->h-3) / text_height(*data->font);
4911 bar = (listsize > height);
4912 w = (bar ? d->w-21 : d->w-5);
4913 fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : (d->fg ? d->fg : scheme[jcTEXTFG]);
4914 bg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_BG] : (d->bg ? d->bg : scheme[jcTEXTBG]);
4915
4916 rectfill(screen, d->x+2, d->y+2, d->x+w+2, d->y+3, bg_color);
4917 vline(screen, d->x+2, d->y+4, d->y+d->h-3, bg_color);
4918 vline(screen, d->x+3, d->y+4, d->y+d->h-3, bg_color);
4919 vline(screen, d->x+w+1, d->y+4, d->y+d->h-3, bg_color);
4920 vline(screen, d->x+w+2, d->y+4, d->y+d->h-3, bg_color);
4921
4922 /* draw box contents */
4923 for(i=0; i<height; i++)
4924 {
4925 if(d->d2+i < listsize)
4926 {
4927 if(d->d2+i == d->d1 && !(d->flags & D_DISABLED))
4928 {
4929 fg = scheme[jcSELFG];
4930 bg = scheme[jcSELBG];
4931 }
4932 else if((sel) && (sel[d->d2+i]))
4933 {
4934 fg = scheme[jcMEDDARK];
4935 bg = scheme[jcSELBG];
4936 }
4937 else
4938 {
4939 fg = fg_color;
4940 bg = bg_color;
4941 }
4942
4943 strncpy(s, data->listFunc(i+d->d2, NULL), 1023);
4944 x = d->x + 4;
4945 y = d->y + 4 + i*text_height(*data->font);
4946 // text_mode(bg);
4947 rectfill(screen, x, y, x+7, y+text_height(*data->font)-1, bg);
4948 x += 8;
4949 len = (int32_t)strlen(s);
4950
4951 while(len > 0 && text_length(*data->font, s) >= d->w - (bar ? 26 : 10))
4952 {
4953 len--;
4954 s[len] = 0;
4955 }
4956
4957 textout_ex(screen, *data->font, s, x, y, fg,bg);
4958 x += text_length(*data->font, s);
4959
4960 if(x <= d->x+w)
4961 rectfill(screen, x, y, d->x+w, y+text_height(*data->font)-1, bg);
4962 }
4963 else
4964 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4965 d->x+w+2, d->y+3+(i+1)*text_height(*data->font), bg_color);
4966 }
4967
4968 if(d->y+4+i*text_height(font) <= d->y+d->h-3)
4969 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4970 d->x+w+2, d->y+d->h-3, bg_color);
4971
4972 /* draw frame, maybe with scrollbar */
4973 _jwin_draw_scrollable_frame(d, listsize, d->d2, height, (d->flags&D_USER)?1:0);
4974 }
4975
4976 /* jwin_list_proc:
4977 * A list box object. The dp field points to a ListData struct containing
4978 * a function which it will call
4979 * to obtain information about the list. This should follow the form:
4980 * char *<list_func_name> (int32_t index, int32_t *list_size);
4981 * If index is zero or positive, the function should return a pointer to
4982 * the string which is to be displayed at position index in the list. If
4983 * index is negative, it should return null and list_size should be set
4984 * to the number of items in the list. The list box object will allow the
4985 * user to scroll through the list and to select items list by clicking
4986 * on them, and if it has the input focus also by using the arrow keys. If
4987 * the D_EXIT flag is set, double clicking on a list item will cause it to
4988 * close the dialog. The index of the selected item is held in the d1
4989 * field, and d2 is used to store how far it has scrolled through the list.
4990 */
4991 int32_t jwin_list_proc(int32_t msg, DIALOG *d, int32_t c)
4992 {
4993 ListData *data = (ListData *)d->dp;
4994 int32_t listsize, i, bottom, height, bar, orig;
4995 char *sel = (char *)d->dp2;
4996 int32_t redraw = FALSE;
4997
4998 switch(msg)
4999 {
5000
5001 case MSG_START:
5002 data->listFunc(-1, &listsize);
5003 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5004 break;
5005
5006 case MSG_DRAW:
5007 _jwin_draw_listbox(d);
5008 break;
5009
5010 case MSG_CLICK:
5011 data->listFunc(-1, &listsize);
5012 height = (d->h-3) / text_height(*data->font);
5013 bar = (listsize > height);
5014
5015 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5016 {
5017 if((sel) && (!(key_shifts & KB_CTRL_FLAG)))
5018 {
5019 for(i=0; i<listsize; i++)
5020 {
5021 if(sel[i])
5022 {
5023 redraw = TRUE;
5024 sel[i] = FALSE;
5025 }
5026 }
5027
5028 if(redraw)
5029 {
5030 object_message(d, MSG_DRAW, 0);
5031 }
5032 }
5033
5034 if(_handle_jwin_listbox_click(d)) GUI_EVENT(d, geCHANGE_SELECTION);
5035
5036 bool rightClicked=(gui_mouse_b()&2)!=0;
5037 while(gui_mouse_b())
5038 {
5039 broadcast_dialog_message(MSG_IDLE, 0);
5040 d->flags |= D_INTERNAL;
5041 bool should_redraw = false;
5042 if(_handle_jwin_listbox_click(d))
5043 {
5044 d->flags &= ~D_INTERNAL;
5045 GUI_EVENT(d, geCHANGE_SELECTION);
5046 should_redraw = true;
5047 }
5048 d->flags &= ~D_INTERNAL;
5049
5050 /* let other objects continue to animate */
5051 int r = broadcast_dialog_message(MSG_IDLE, 0);
5052 if (r & D_REDRAWME) should_redraw = true;
5053
5054 if (should_redraw)
5055 {
5056 update_hw_screen();
5057 }
5058 }
5059
5060 if(rightClicked)
5061 {
5062 GUI_EVENT(d, geRCLICK);
5063 if((d->flags&(D_USER<<1))!=0 && d->dp3)
5064 {
5065 typedef void (*funcType)(int32_t /* index */, int32_t /* x */, int32_t /* y */);
5066 funcType func=reinterpret_cast<funcType>(d->dp3);
5067 func(d->d1, gui_mouse_x(), gui_mouse_y());
5068 }
5069 }
5070
5071 if(d->flags & D_USER)
5072 {
5073 if(listsize)
5074 {
5075 clear_keybuf();
5076 return D_CLOSE;
5077 }
5078 }
5079
5080 return D_REDRAWME;
5081 }
5082 else
5083 {
5084 _handle_jwin_scrollable_scroll_click(d, listsize, &d->d2, *data->font);
5085 }
5086
5087 break;
5088
5089 case MSG_DCLICK:
5090 // Ignore double right-click
5091 if((gui_mouse_b()&2)!=0)
5092 break;
5093
5094 data->listFunc(-1, &listsize);
5095 height = (d->h-3) / text_height(*data->font);
5096 bar = (listsize > height);
5097
5098 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5099 {
5100 if(listsize)
5101 {
5102 i = d->d1;
5103 object_message(d, MSG_CLICK, 0);
5104
5105 if(i == d->d1)
5106 {
5107 if(d->flags & D_EXIT)
5108 return D_CLOSE;
5109 else GUI_EVENT(d, geDCLICK);
5110 }
5111 }
5112 }
5113
5114 break;
5115
5116 case MSG_KEY:
5117 data->listFunc(-1, &listsize);
5118
5119 if((listsize) && (d->flags & D_EXIT))
5120 return D_CLOSE;
5121
5122 break;
5123
5124 case MSG_WANTFOCUS:
5125 return D_WANTFOCUS;
5126
5127 case MSG_WANTWHEEL:
5128 return 1;
5129
5130 case MSG_WHEEL:
5131 data->listFunc(-1, &listsize);
5132 height = (d->h-4) / text_height(*data->font);
5133
5134 if(height < listsize)
5135 {
5136 int32_t delta = (height > 3) ? 3 : 1;
5137
5138 if(c > 0)
5139 {
5140 i = MAX(0, d->d2-delta);
5141 }
5142 else
5143 {
5144 i = MIN(listsize-height, d->d2+delta);
5145 }
5146
5147 if(i != d->d2)
5148 {
5149 d->d2 = i;
5150 object_message(d, MSG_DRAW, 0);
5151 GUI_EVENT(d, geCHANGE_SELECTION);
5152 return D_REDRAWME;
5153 }
5154 }
5155
5156 break;
5157
5158 case MSG_CHAR:
5159 data->listFunc(-1,&listsize);
5160
5161 if(listsize)
5162 {
5163 c >>= 8;
5164
5165 bottom = d->d2 + (d->h-3)/text_height(*data->font) - 1;
5166
5167 if(bottom >= listsize-1)
5168 bottom = listsize-1;
5169
5170 orig = d->d1;
5171
5172 if(c == KEY_UP)
5173 d->d1--;
5174 else if(c == KEY_DOWN)
5175 d->d1++;
5176 else if(c == KEY_HOME)
5177 d->d1 = 0;
5178 else if(c == KEY_END)
5179 d->d1 = listsize-1;
5180 else if(c == KEY_PGUP)
5181 {
5182 if(d->d1 > d->d2)
5183 d->d1 = d->d2;
5184 else
5185 d->d1 -= (bottom - d->d2);
5186 }
5187 else if(c == KEY_PGDN)
5188 {
5189 if(d->d1 < bottom)
5190 d->d1 = bottom;
5191 else
5192 d->d1 += (bottom - d->d2);
5193 }
5194 else
5195 return D_O_K;
5196
5197 if(sel)
5198 {
5199 if(!(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG)))
5200 {
5201 for(i=0; i<listsize; i++)
5202 sel[i] = FALSE;
5203 }
5204 else if(key_shifts & KB_SHIFT_FLAG)
5205 {
5206 for(i=MIN(orig, d->d1); i<=MAX(orig, d->d1); i++)
5207 {
5208 if(key_shifts & KB_CTRL_FLAG)
5209 sel[i] = (i != d->d1);
5210 else
5211 sel[i] = TRUE;
5212 }
5213 }
5214 }
5215
5216 /* if we changed something, better redraw... !Also bounds the index! */
5217 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5218
5219 GUI_EVENT(d, geCHANGE_SELECTION);
5220
5221 if (d->d1 != orig)
5222 d->flags |= D_DIRTY;
5223 return D_USED_CHAR;
5224 }
5225
5226 break;
5227 }
5228
5229 return D_O_K;
5230 }
5231
5232
5233 /*
5234 Effectively an overload of jwin_list_proc that i used eclusively for abc lists.
5235 This calls the appropriate form of drawing for those listers.
5236 */
5237 int32_t jwin_do_abclist_proc(int32_t msg, DIALOG *d, int32_t c)
5238 {
5239 ListData *data = (ListData *)d->dp;
5240 int32_t listsize, i, bottom, height, bar, orig, h;
5241 int32_t ret = D_O_K;
5242 bool revert_size = false;
5243 if((d->flags & D_RESIZED) == 0)
5244 {
5245 h = d->h;
5246 d->h -= text_height(*data->font);
5247 d->flags |= D_RESIZED;
5248 revert_size = true;
5249 }
5250 char *sel = (char *)d->dp2;
5251 int32_t redraw = FALSE;
5252
5253 switch(msg)
5254 {
5255
5256 case MSG_START:
5257 data->listFunc(-1, &listsize);
5258 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5259 break;
5260
5261 case MSG_DRAW:
5262 _jwin_draw_abclistbox(d);
5263 break;
5264
5265 case MSG_CLICK:
5266 if(gui_mouse_y() > (d->y+d->h-1))
5267 {
5268 if(gui_mouse_y() > (d->y+d->h+2))
5269 {
5270 //Clicked on the box displaying the patternmatch
5271 }
5272 else {} //Clicked between the lister and patternmatch
5273 }
5274 else //Clicked the lister
5275 {
5276 data->listFunc(-1, &listsize);
5277 height = (d->h-3) / text_height(*data->font);
5278 bar = (listsize > height);
5279
5280 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5281 {
5282 if((sel) && (!(key_shifts & KB_CTRL_FLAG)))
5283 {
5284 for(i=0; i<listsize; i++)
5285 {
5286 if(sel[i])
5287 {
5288 redraw = TRUE;
5289 sel[i] = FALSE;
5290 }
5291 }
5292
5293 if(redraw)
5294 {
5295 object_message(d, MSG_DRAW, 0);
5296 }
5297 }
5298
5299 if(_handle_jwin_listbox_click(d)) GUI_EVENT(d, geCHANGE_SELECTION);
5300
5301 bool rightClicked=(gui_mouse_b()&2)!=0;
5302 while(gui_mouse_b())
5303 {
5304 broadcast_dialog_message(MSG_IDLE, 0);
5305 d->flags |= D_INTERNAL;
5306 if(_handle_jwin_listbox_click(d))
5307 {
5308 d->flags &= ~D_INTERNAL;
5309 GUI_EVENT(d, geCHANGE_SELECTION);
5310 update_hw_screen();
5311 }
5312 d->flags &= ~D_INTERNAL;
5313 rest(1);
5314 }
5315
5316 if(rightClicked)
5317 {
5318 GUI_EVENT(d, geRCLICK);
5319 if((d->flags&(D_USER<<1))!=0 && d->dp3)
5320 {
5321 typedef void (*funcType)(int32_t /* index */, int32_t /* x */, int32_t /* y */);
5322 funcType func=reinterpret_cast<funcType>(d->dp3);
5323 func(d->d1, gui_mouse_x(), gui_mouse_y());
5324 }
5325 }
5326
5327 if(d->flags & D_USER)
5328 {
5329 if(listsize)
5330 {
5331 clear_keybuf();
5332 ret = D_CLOSE;
5333 }
5334 }
5335
5336 return D_REDRAWME;
5337 }
5338 else
5339 {
5340 _handle_jwin_scrollable_scroll_click(d, listsize, &d->d2, *data->font);
5341 }
5342 }
5343 break;
5344
5345 case MSG_DCLICK:
5346 // Ignore double right-click
5347 if((gui_mouse_b()&2)!=0)
5348 break;
5349
5350 if(gui_mouse_y() > (d->y+d->h-1))
5351 {
5352 if(gui_mouse_y() > (d->y+d->h+2))
5353 {
5354 //Clicked on the box displaying the patternmatch
5355 }
5356 else {} //Clicked between the lister and patternmatch
5357 }
5358 else //Clicked the lister
5359 {
5360 data->listFunc(-1, &listsize);
5361 height = (d->h-3) / text_height(*data->font);
5362 bar = (listsize > height);
5363
5364 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5365 {
5366 if(listsize)
5367 {
5368 i = d->d1;
5369 object_message(d, MSG_CLICK, 0);
5370
5371 if(i == d->d1)
5372 {
5373 if(d->flags & D_EXIT)
5374 ret = D_CLOSE;
5375 else GUI_EVENT(d, geDCLICK);
5376 }
5377 }
5378 }
5379 }
5380 break;
5381
5382 case MSG_KEY:
5383 data->listFunc(-1, &listsize);
5384
5385 if((listsize) && (d->flags & D_EXIT))
5386 ret = D_CLOSE;
5387
5388 break;
5389
5390 case MSG_WANTFOCUS:
5391 ret = D_WANTFOCUS;
5392 break;
5393
5394 case MSG_WANTWHEEL:
5395 return 1;
5396
5397 case MSG_WHEEL:
5398 data->listFunc(-1, &listsize);
5399 height = (d->h-4) / text_height(*data->font);
5400
5401 if(height < listsize)
5402 {
5403 int32_t delta = (height > 3) ? 3 : 1;
5404
5405 if(c > 0)
5406 {
5407 i = MAX(0, d->d2-delta);
5408 }
5409 else
5410 {
5411 i = MIN(listsize-height, d->d2+delta);
5412 }
5413
5414 if(i != d->d2)
5415 {
5416 d->d2 = i;
5417 object_message(d, MSG_DRAW, 0);
5418 GUI_EVENT(d, geCHANGE_SELECTION);
5419 ret |= D_REDRAWME;
5420 }
5421 }
5422
5423 break;
5424
5425 case MSG_CHAR:
5426 data->listFunc(-1,&listsize);
5427
5428 if(listsize)
5429 {
5430 c >>= 8;
5431
5432 bottom = d->d2 + (d->h-3)/text_height(*data->font) - 1;
5433
5434 if(bottom >= listsize-1)
5435 bottom = listsize-1;
5436
5437 orig = d->d1;
5438
5439 if(c == KEY_UP)
5440 d->d1--;
5441 else if(c == KEY_DOWN)
5442 d->d1++;
5443 else if(c == KEY_HOME)
5444 d->d1 = 0;
5445 else if(c == KEY_END)
5446 d->d1 = listsize-1;
5447 else if(c == KEY_PGUP)
5448 {
5449 if(d->d1 > d->d2)
5450 d->d1 = d->d2;
5451 else
5452 d->d1 -= (bottom - d->d2);
5453 }
5454 else if(c == KEY_PGDN)
5455 {
5456 if(d->d1 < bottom)
5457 d->d1 = bottom;
5458 else
5459 d->d1 += (bottom - d->d2);
5460 }
5461 else
5462 break; //return D_O_K;
5463
5464 if(sel)
5465 {
5466 if(!(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG)))
5467 {
5468 for(i=0; i<listsize; i++)
5469 sel[i] = FALSE;
5470 }
5471 else if(key_shifts & KB_SHIFT_FLAG)
5472 {
5473 for(i=MIN(orig, d->d1); i<=MAX(orig, d->d1); i++)
5474 {
5475 if(key_shifts & KB_CTRL_FLAG)
5476 sel[i] = (i != d->d1);
5477 else
5478 sel[i] = TRUE;
5479 }
5480 }
5481 }
5482
5483 /* if we changed something, better redraw... */
5484 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5485
5486 GUI_EVENT(d, geCHANGE_SELECTION);
5487
5488 if (d->d1 != orig)
5489 d->flags |= D_DIRTY;
5490 ret = D_USED_CHAR;
5491 }
5492
5493 break;
5494 }
5495 if(revert_size)
5496 {
5497 d->h = h;
5498 d->flags &= ~D_RESIZED;
5499 }
5500 return ret;
5501 }
5502
5503 /* _jwin_draw_textbox:
5504 * Helper function to draw a textbox object.
5505 */
5506 void _jwin_draw_textbox(char *thetext, int32_t *listsize, int32_t draw, int32_t offset,
5507 int32_t wword, int32_t tabsize, int32_t x, int32_t y, int32_t w, int32_t h,
5508 int32_t disabled)
5509 {
5510 int32_t fg = scheme[jcTEXTFG];
5511 int32_t bg = scheme[jcTEXTBG];
5512 int32_t y1 = y+4;
5513 int32_t x1;
5514 int32_t len;
5515 int32_t ww = w-10;
5516 char s[16] = {0};
5517 char text[16] = {0};
5518 char space[16] = {0};
5519 char *printed = text;
5520 char *scanned = text;
5521 char *oldscan = text;
5522 char *ignore = NULL;
5523 char *tmp, *ptmp;
5524 int32_t width;
5525 int32_t line = 0;
5526 int32_t i = 0;
5527 int32_t noignore;
5528 // int32_t rtm;
5529
5530 usetc(s+usetc(s, '.'), 0);
5531 usetc(text+usetc(text, ' '), 0);
5532 usetc(space+usetc(space, ' '), 0);
5533
5534 /* find the correct text */
5535 if(thetext != NULL)
5536 {
5537 printed = thetext;
5538 scanned = thetext;
5539 }
5540
5541 /* choose the text color */
5542 if(disabled)
5543 {
5544 fg = scheme[jcDISABLED_FG];
5545 bg = scheme[jcDISABLED_BG];
5546 }
5547
5548 /* do some drawing setup */
5549 if(draw)
5550 {
5551 /* initial start blanking at the top */
5552 rectfill(screen, x+2, y+2, x+w-2, y1-1, bg);
5553 }
5554
5555 // rtm = text_mode(bg);
5556
5557 /* loop over the entire string */
5558 for(;;)
5559 {
5560 width = 0;
5561
5562 /* find the next break */
5563 while(ugetc(scanned))
5564 {
5565 /* check for a forced break */
5566 if(ugetc(scanned) == '\n')
5567 {
5568 scanned += uwidth(scanned);
5569
5570 /* we are done parsing the line end */
5571 break;
5572 }
5573
5574 /* the next character length */
5575 usetc(s+usetc(s, ugetc(scanned)), 0);
5576 len = text_length(font, s);
5577
5578 /* modify length if its a tab */
5579 if(ugetc(s) == '\t')
5580 len = tabsize * text_length(font, space);
5581
5582 /* check for the end of a line by excess width of next char */
5583 if(width+len >= ww)
5584 {
5585 /* we have reached end of line do we go back to find start */
5586 if(wword)
5587 {
5588 /* remember where we were */
5589 oldscan = scanned;
5590 noignore = FALSE;
5591
5592 /* go backwards looking for start of word */
5593 while(!uisspace(ugetc(scanned)))
5594 {
5595 /* don't wrap too far */
5596 if(scanned == printed)
5597 {
5598 /* the whole line is filled, so stop here */
5599 tmp = ptmp = scanned;
5600
5601 while(ptmp != oldscan)
5602 {
5603 ptmp = tmp;
5604 tmp += uwidth(tmp);
5605 }
5606
5607 scanned = ptmp;
5608 noignore = TRUE;
5609 break;
5610 }
5611
5612 /* look further backwards to wrap */
5613 tmp = ptmp = printed;
5614
5615 while(tmp < scanned)
5616 {
5617 ptmp = tmp;
5618 tmp += uwidth(tmp);
5619 }
5620
5621 scanned = ptmp;
5622 }
5623
5624 /* put the space at the end of the line */
5625 if(!noignore)
5626 {
5627 ignore = scanned;
5628 scanned += uwidth(scanned);
5629 }
5630 else
5631 ignore = NULL;
5632
5633 /* check for endline at the convenient place */
5634 if(ugetc(scanned) == '\n')
5635 scanned += uwidth(scanned);
5636 }
5637
5638 /* we are done parsing the line end */
5639 break;
5640 }
5641
5642 /* the character can be added */
5643 scanned += uwidth(scanned);
5644 width += len;
5645 }
5646
5647 /* check if we are to print it */
5648 if((draw) && (line >= offset) && (y1+text_height(font) < (y+h-3)))
5649 {
5650 x1 = x+4;
5651
5652 /* the initial blank bit */
5653 rectfill(screen, x+2, y1, x1-1, y1+text_height(font), bg);
5654
5655 /* print up to the marked character */
5656 while(printed != scanned)
5657 {
5658 /* do special stuff for each character */
5659 switch(ugetc(printed))
5660 {
5661
5662 case '\r':
5663 case '\n':
5664 /* don't print endlines in the text */
5665 break;
5666
5667 /* possibly expand the tabs */
5668 case '\t':
5669 for(i=0; i<tabsize; i++)
5670 {
5671 usetc(s+usetc(s, ' '), 0);
5672 textout_ex(screen, font, s, x1, y1, fg,bg);
5673 x1 += text_length(font, s);
5674 }
5675
5676 break;
5677
5678 /* print a normal character */
5679 default:
5680 if(printed != ignore)
5681 {
5682 usetc(s+usetc(s, ugetc(printed)), 0);
5683 textout_ex(screen, font, s, x1, y1, fg,bg);
5684 x1 += text_length(font, s);
5685 }
5686 }
5687
5688 /* goto the next character */
5689 printed += uwidth(printed);
5690 }
5691
5692 /* the last blank bit */
5693 if(x1 <= x+w-3)
5694 rectfill(screen, x1, y1, x+w-2, y1+text_height(font)-1, bg);
5695
5696 /* print the line end */
5697 y1 += text_height(font);
5698 }
5699
5700 printed = scanned;
5701
5702 /* we have done a line */
5703 line++;
5704
5705 /* check if we are at the end of the string */
5706 if(!ugetc(printed))
5707 {
5708 /* the under blank bit */
5709 if(draw)
5710 rectfill(screen, x+1, y1, x+w-2, y+h-1, bg);
5711
5712 /* tell how many lines we found */
5713 *listsize = line;
5714 // text_mode(rtm);
5715 return;
5716 }
5717 }
5718
5719 // text_mode(rtm);
5720 }
5721
5722 /* jwin_textbox_proc:
5723 * A text box object. The dp field points to a char * which is the text
5724 * to be displayed in the text box. If the text is long, there will be
5725 * a vertical scrollbar on the right hand side of the object which can
5726 * be used to scroll through the text. The default is to print the text
5727 * with word wrapping, but if the D_SELECTED flag is set, the text will
5728 * be printed with character wrapping. The d1 field is used internally
5729 * to store the number of lines of text, and d2 is used to store how far
5730 * it has scrolled through the text.
5731 */
5732 int32_t jwin_textbox_proc(int32_t msg, DIALOG *d, int32_t c)
5733 {
5734 int32_t height, bar, ret = D_O_K;
5735 int32_t start, top, bottom,l;
5736 int32_t used, delta;
5737 // int32_t fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
5738
5739 FONT *oldfont=NULL;
5740
5741 if(d->dp2!=NULL)
5742 {
5743 oldfont=font;
5744 font=(FONT*)d->dp2;
5745 }
5746
5747 /* calculate the actual height */
5748 height = (d->h-4) / text_height(font);
5749
5750 switch(msg)
5751 {
5752
5753 case MSG_START:
5754 /* measure how many lines of text we contain */
5755 _jwin_draw_textbox((char*)d->dp, &d->d1,
5756 0, /* DONT DRAW anything */
5757 d->d2, !(d->flags & D_SELECTED), 8,
5758 d->x, d->y, d->w, d->h,
5759 (d->flags & D_DISABLED));
5760 break;
5761
5762 case MSG_DRAW:
5763 /* tell the object to sort of draw, but only calculate the listsize */
5764 _jwin_draw_textbox((char*)d->dp, &d->d1,
5765 0, /* DONT DRAW anything */
5766 d->d2, !(d->flags & D_SELECTED), 8,
5767 d->x, d->y, d->w, d->h,
5768 (d->flags & D_DISABLED));
5769
5770 if(d->d1 > height)
5771 {
5772 bar = 16;
5773 }
5774 else
5775 {
5776 bar = 0;
5777 d->d2 = 0;
5778 }
5779
5780 /* now do the actual drawing */
5781 _jwin_draw_textbox((char*)d->dp, &d->d1, 1, d->d2,
5782 !(d->flags & D_SELECTED), 8,
5783 d->x, d->y, d->w-bar-1, d->h,
5784 (d->flags & D_DISABLED));
5785
5786 /* draw the frame around */
5787 _jwin_draw_scrollable_frame(d, d->d1, d->d2, height, 0);
5788 break;
5789
5790 case MSG_CLICK:
5791 /* figure out if it's on the text or the scrollbar */
5792 bar = (d->d1 > height);
5793
5794 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5795 {
5796 /* clicked on the text area */
5797 ret = D_O_K;
5798 }
5799 else
5800 {
5801 /* clicked on the scroll area */
5802 _handle_jwin_scrollable_scroll_click(d, d->d1, &d->d2, font);
5803 }
5804
5805 break;
5806
5807 case MSG_WANTWHEEL:
5808 return 1;
5809
5810 case MSG_WHEEL:
5811 l = (d->h-8)/text_height(font);
5812 delta = (l > 3) ? 3 : 1;
5813
5814 // scroll, making sure that the list stays in bounds
5815 start = d->d2;
5816 d->d2 = (c > 0) ? MAX(0, d->d2-delta) : MIN(d->d1-l, d->d2+delta);
5817
5818 // if we changed something, better redraw...
5819 if(d->d2 != start)
5820 {
5821 d->flags |= D_DIRTY;
5822 }
5823
5824 ret = D_O_K;
5825 break;
5826
5827 case MSG_CHAR:
5828 start = d->d2;
5829 used = D_USED_CHAR;
5830
5831 if(d->d1 > 0)
5832 {
5833 if(d->d2 > 0)
5834 top = d->d2+1;
5835 else
5836 top = 0;
5837
5838 l = (d->h-3)/text_height(font);
5839
5840 bottom = d->d2 + l - 1;
5841
5842 if(bottom >= d->d1-1)
5843 bottom = d->d1-1;
5844 else
5845 bottom--;
5846
5847 if((c>>8) == KEY_UP)
5848 d->d2--;
5849 else if((c>>8) == KEY_DOWN)
5850 d->d2++;
5851 else if((c>>8) == KEY_HOME)
5852 d->d2 = 0;
5853 else if((c>>8) == KEY_END)
5854 d->d2 = d->d1-l;
5855 else if((c>>8) == KEY_PGUP)
5856 d->d2 = d->d2-(bottom-top);
5857 else if((c>>8) == KEY_PGDN)
5858 d->d2 = d->d2+(bottom-top);
5859 else
5860 used = D_O_K;
5861
5862 /* make sure that the list stays in bounds */
5863 if(d->d2 > d->d1-l)
5864 d->d2 = d->d1-l;
5865
5866 if(d->d2 < 0)
5867 d->d2 = 0;
5868 }
5869 else
5870 used = D_O_K;
5871
5872 /* if we changed something, better redraw... */
5873 if(d->d2 != start)
5874 {
5875 d->proc(MSG_DRAW, d, 0);
5876 }
5877
5878 ret = used;
5879 break;
5880
5881 case MSG_WANTFOCUS:
5882
5883 /* if we don't have a scrollbar we can't do anything with the focus */
5884 if(d->d1 > height)
5885 ret = D_WANTFOCUS;
5886
5887 break;
5888
5889 default:
5890 ret = D_O_K;
5891 }
5892
5893 if(d->dp2!=NULL)
5894 {
5895 font=oldfont;
5896 }
5897
5898 return ret;
5899 }
5900
5901 /* jwin_slider_proc:
5902 * A slider control object. This object returns a value in d2, in the
5903 * range from 0 to d1. It will display as a vertical slider if h is
5904 * greater than or equal to w; otherwise, it will display as a horizontal
5905 * slider. dp can contain an optional bitmap to use for the slider handle;
5906 * dp2 can contain an optional callback function, which is called each
5907 * time d2 changes. The callback function should have the following
5908 * prototype:
5909 *
5910 * int32_t function(void *dp3, int32_t d2);
5911 *
5912 * The d_slider_proc object will return the value of the callback function.
5913 */
5914 int32_t jwin_slider_proc(int32_t msg, DIALOG *d, int32_t c)
5915 {
5916 BITMAP *slhan = NULL;
5917 int32_t sfg; /* slider foreground color */
5918 int32_t vert = TRUE; /* flag: is slider vertical? */
5919 int32_t hh = 7; /* handle height (width for horizontal sliders) */
5920 int32_t hmar; /* handle margin */
5921 int32_t slp; /* slider position */
5922 int32_t irange;
5923 int32_t slx, sly, slh, slw;
5924 fixed slratio, slmax, slpos;
5925 ASSERT(d);
5926
5927 /* check for slider direction */
5928 if(d->h < d->w)
5929 {
5930 vert = FALSE;
5931 }
5932
5933 /* set up the metrics for the control */
5934 if(d->dp != NULL)
5935 {
5936 slhan = (BITMAP *)d->dp;
5937
5938 if(vert)
5939 {
5940 hh = slhan->h;
5941 }
5942 else
5943 {
5944 hh = slhan->w;
5945 }
5946 }
5947
5948 hmar = hh/2;
5949 irange = (vert) ? d->h : d->w;
5950 slmax = itofix(irange-hh);
5951 slratio = slmax / (d->d1);
5952 slpos = slratio * d->d2;
5953 slp = fixtoi(slpos);
5954
5955 switch(msg)
5956 {
5957 case MSG_DRAW:
5958 // sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : scheme[jcBOXFG];
5959 sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : scheme[jcBOXFG];
5960
5961 if(vert)
5962 {
5963 rectfill(screen, d->x, d->y, d->x+d->w/2-2, d->y+d->h, scheme[jcBOX]);
5964 rectfill(screen, d->x+d->w/2-1, d->y, d->x+d->w/2+1, d->y+d->h, sfg);
5965 rectfill(screen, d->x+d->w/2+2, d->y, d->x+d->w, d->y+d->h, scheme[jcBOX]);
5966 }
5967 else
5968 {
5969 rectfill(screen, d->x, d->y, d->x+d->w, d->y+d->h/2-2, scheme[jcBOX]);
5970 rectfill(screen, d->x, d->y+d->h/2-1, d->x+d->w, d->y+d->h/2+1, sfg);
5971 rectfill(screen, d->x, d->y+d->h/2+2, d->x+d->w, d->y+d->h, scheme[jcBOX]);
5972 }
5973
5974 if(d->flags & D_GOTFOCUS)
5975 {
5976 _dotted_rect(d->x, d->y, d->x+d->w, d->y+d->h, sfg, scheme[jcBOX]);
5977 }
5978
5979 /* okay, background and slot are drawn, now draw the handle */
5980 if(slhan)
5981 {
5982 if(vert)
5983 {
5984 slx = d->x+(d->w/2)-(slhan->w/2);
5985 sly = d->y+d->h-(hh+slp);
5986 }
5987 else
5988 {
5989 slx = d->x+slp;
5990 sly = d->y+(d->h/2)-(slhan->h/2);
5991 }
5992
5993 draw_sprite(screen, slhan, slx, sly);
5994 }
5995 else
5996 {
5997 /* draw default handle */
5998 if(vert)
5999 {
6000 slx = d->x;
6001 sly = d->y+d->h-(hh+slp);
6002 slw = d->w;
6003 slh = hh;
6004 }
6005 else
6006 {
6007 slx = d->x+slp;
6008 sly = d->y;
6009 slw = hh;
6010 slh = d->h;
6011 }
6012
6013 jwin_draw_button(screen, slx, sly, slw+1, slh+1, d->flags&D_DISABLED?3:0, 0);
6014 }
6015
6016 break;
6017
6018 default:
6019 return d_jslider_proc(msg, d, c);
6020 }
6021
6022 return D_O_K;
6023 }
6024
6025 const char* rowpref(int32_t row, bool alt)
6026 {
6027 static const char *lcol = "Level Colors", *syscol = "System Colors", *bosscol = "Boss Colors", *thmcol = "Theme Colors", *nlcol="";
6028 switch(row)
6029 {
6030 case 2: case 3: case 4: case 9:
6031 return lcol;
6032 case 14:
6033 return alt ? syscol : bosscol;
6034 case 15:
6035 return thmcol;
6036 default:
6037 return nlcol;
6038 }
6039 }
6040
6041 byte getHighlightColor(int32_t c)
6042 {
6043 RGB col;
6044 get_color(c, &col);
6045 return getHighlightColor(col);
6046 }
6047
6048 byte getHighlightColor(RGB const& col)
6049 {
6050 double lum = (pow(col.r/64.0, 2.2) * 0.2126) +
6051 (pow(col.g/64.0, 2.2) * 0.7152) +
6052 (pow(col.b/64.0, 2.2) * 0.0722);
6053 return lum < 0.4 ? vc(15) : vc(0);
6054 //Old -Em
6055 // byte bright = (col.r >= 32) + (col.g >= 32) + (col.b >= 32);
6056 // byte sbright = (col.r >= 48) + (col.g >= 48) + (col.b >= 48);
6057 // byte highlightColor = vc(7); //sysgray
6058 // if(bright >= 2)
6059 // {
6060 // if(sbright >= 2)
6061 // highlightColor = vc(0); //sysblack
6062 // else highlightColor = vc(8); //sysdarkgray
6063 // }
6064 // else if(!bright)
6065 // highlightColor = vc(15); //syswhite
6066 // return highlightColor;
6067 }
6068
6069 int32_t jwin_selcolor_proc(int32_t msg, DIALOG *d, int32_t c)
6070 {
6071 int32_t ret = D_O_K;
6072 if(!d->d2) d->d2 = 12;
6073 bool alt = d->d2 > 16;
6074 int32_t numcsets = alt ? 16 : d->d2;
6075 int32_t numcol = numcsets*0x10;
6076 if(msg==MSG_START)
6077 {
6078 d->w = d->h = (16*8) * 1.5;
6079 }
6080 int32_t csz = 12;
6081 d->w = csz * 16;
6082 d->h = csz * numcsets;
6083 switch(msg)
6084 {
6085 case MSG_DRAW:
6086 {
6087 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_ETCHED);
6088 for(int32_t c = 0; c < numcol; ++c)
6089 {
6090 int32_t x = (c%16)*csz, y = (c/16)*csz;
6091 rectfill(screen, d->x+x, d->y+y, d->x+x+csz-1, d->y+y+csz-1, c);
6092 if(c == d->d1)
6093 {
6094 byte highlightColor = getHighlightColor(c);
6095 rect(screen, d->x+x+0, d->y+y+0, d->x+x+csz-1, d->y+y+csz-1, highlightColor);
6096 rect(screen, d->x+x+1, d->y+y+1, d->x+x+csz-2, d->y+y+csz-2, highlightColor);
6097 }
6098 }
6099
6100 FONT *oldfont = font;
6101
6102 if(d->dp2)
6103 {
6104 font = (FONT*)d->dp2;
6105 }
6106
6107 char buf[32]={0};
6108 for(int32_t col = 0; col < 16; ++col)
6109 {
6110 sprintf(buf, "%X", col);
6111 gui_textout_ln(screen, (uint8_t*)buf, d->x + (csz*col) + (csz/2), d->y-3-text_height(font), scheme[jcBOXFG], scheme[jcBOX], 1);
6112 }
6113 for(int32_t row = 0; row < numcsets; ++row)
6114 {
6115 sprintf(buf, "%s 0x%02X", rowpref(row, alt), row*16);
6116 gui_textout_ln(screen, (uint8_t*)buf, d->x-3, d->y + (csz*row) + (csz-text_height(font))/2, scheme[jcBOXFG], scheme[jcBOX], 2);
6117 }
6118
6119 font = oldfont;
6120 break;
6121 }
6122
6123 case MSG_CLICK:
6124 {
6125 if(mouse_in_rect(d->x, d->y, d->x+d->w-1, d->y+d->h-1))
6126 {
6127 int32_t col = ((gui_mouse_x() - d->x) / csz) + 16*((gui_mouse_y() - d->y) / csz);
6128
6129 if(col>-1 && col != d->d1)
6130 {
6131 d->d1 = col;
6132 ret |= D_REDRAWME;
6133 }
6134 ret |= D_WANTFOCUS;
6135 }
6136 break;
6137 }
6138
6139 case MSG_WANTFOCUS:
6140 case MSG_LOSTFOCUS:
6141 case MSG_KEY:
6142 ret = D_WANTFOCUS;
6143 break;
6144
6145 case MSG_CHAR:
6146 {
6147 ret = D_USED_CHAR | D_REDRAWME;
6148 switch(c>>8)
6149 {
6150 case KEY_LEFT:
6151 {
6152 if(d->d1 % 0x10)
6153 --d->d1;
6154 break;
6155 }
6156 case KEY_RIGHT:
6157 {
6158 if(d->d1 % 0x10 != 0x0F)
6159 ++d->d1;
6160 break;
6161 }
6162 case KEY_UP:
6163 {
6164 if(d->d1 / 0x10)
6165 d->d1 -= 0x10;
6166 break;
6167 }
6168 case KEY_DOWN:
6169 {
6170 if(d->d1 / 0x10 != numcsets)
6171 d->d1 += 0x10;
6172 break;
6173 }
6174 case KEY_ENTER:
6175 {
6176 ret = D_CLOSE;
6177 break;
6178 }
6179 default: ret = D_O_K;
6180 }
6181 break;
6182 }
6183 }
6184 return ret;
6185 }
6186
6187 static DIALOG selcolor_dlg[] =
6188 {
6189 { jwin_win_proc, 0, 0, 306, 63+16*8, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"Select Color", NULL, NULL },
6190 { jwin_button_proc, 75, 40+16*8, 61, 21, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"OK", NULL, NULL },
6191 { jwin_button_proc, 164, 40+16*8, 61, 21, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"Cancel", NULL, NULL },
6192 { jwin_selcolor_proc, 156-64, 34, 16*8, 16*8, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6193
6194 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6195 };
6196
6197 int32_t jwin_color_swatch(int32_t msg, DIALOG *d, int32_t c)
6198 {
6199 int32_t ret = D_O_K;
6200
6201 switch(msg)
6202 {
6203 case MSG_START:
6204 {
6205 if(d->d2 < 1) d->d2 = 12;
6206 else if(d->d2 > 17) d->d2 = 17;
6207 break;
6208 }
6209
6210 case MSG_DRAW:
6211 {
6212 if(!d->d1 || (d->flags&D_DISABLED))
6213 {
6214 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1,
6215 (d->flags&D_DISABLED) ? scheme[jcDISABLED_BG] : vc(0));
6216 line(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1, vc(15));
6217 line(screen, d->x, d->y+d->h-1, d->x+d->w-1, d->y, vc(15));
6218 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_DEEP);
6219 }
6220 else
6221 {
6222 int32_t c;
6223 switch(d->d1) //special cases
6224 {
6225 case BLACK:
6226 c = vc(0);
6227 break;
6228 case WHITE:
6229 c = vc(15);
6230 break;
6231 default:
6232 c = d->d1;
6233 break;
6234 }
6235 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1, c);
6236 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_ETCHED);
6237 }
6238 break;
6239 }
6240
6241 case MSG_CLICK:
6242 {
6243 if(d->flags&(D_READONLY|D_DISABLED)) break;
6244 selcolor_dlg[0].dp2 = get_zc_font(font_lfont);
6245 selcolor_dlg[3].bg = scheme[jcBOXFG];
6246 selcolor_dlg[3].fg = scheme[jcBOX];
6247 selcolor_dlg[3].d1 = d->d1;
6248 selcolor_dlg[3].d2 = d->d2;
6249 large_dialog(selcolor_dlg);
6250
6251 while(gui_mouse_b()) rest(1); //wait for mouseup
6252
6253 //!TODO Move this out of jwin, and do better palette management.
6254 //!TODO Allow loading different level palettes, sprite palettes, etc via buttons
6255 PALETTE oldpal;
6256 get_palette(oldpal);
6257 bool alt = d->d2 > 16;
6258 if(!alt)
6259 {
6260 PALETTE foopal;
6261 get_palette(foopal);
6262 foopal[BLACK] = _RGB(0,0,0);
6263 foopal[WHITE] = _RGB(255,255,255);
6264 zc_set_palette(foopal);
6265 }
6266
6267 jwin_center_dialog(selcolor_dlg);
6268 int32_t val = do_zqdialog(selcolor_dlg, 3);
6269 ret = D_REDRAW;
6270
6271 zc_set_palette(oldpal);
6272 if(val == 1 || val == 3)
6273 {
6274 d->d1 = selcolor_dlg[3].d1;
6275 GUI_EVENT(d, geCHANGE_VALUE);
6276 ret |= D_REDRAWME;
6277 }
6278 if(d->flags & D_EXIT)
6279 return D_CLOSE;
6280 break;
6281 }
6282 }
6283 return ret;
6284 }
6285
6286 static DIALOG alert_dialog[] =
6287 {
6288 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
6289 { jwin_win_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6290 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6291 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6292 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6293 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6294 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6295 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6296 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6297 };
6298
6299 #define A_S1 1
6300 #define A_S2 2
6301 #define A_S3 3
6302 #define A_B1 4
6303 #define A_B2 5
6304 #define A_B3 6
6305
6306 /* jwin_alert3:
6307 * Displays a simple alert box, containing three lines of text (s1-s3),
6308 * and with either one, two, or three buttons. The text for these buttons
6309 * is passed in b1, b2, and b3 (NULL for buttons which are not used), and
6310 * the keyboard shortcuts in c1 and c2. Returns 1, 2, or 3 depending on
6311 * which button was selected.
6312 */
6313 int32_t jwin_alert3(const char *title, const char *s1, const char *s2, const char *s3, const char *b1, const char *b2, const char *b3, int32_t c1, int32_t c2, int32_t c3, FONT *title_font)
6314 {
6315 int32_t maxlen = 0;
6316 int32_t len1, len2, len3;
6317 int32_t avg_w = text_length(font, " ");
6318 int32_t avg_h = text_height(font)+1;
6319 int32_t buttons = 0;
6320 int32_t yofs = (title ? 22 : 0);
6321 int32_t b[3];
6322 int32_t c;
6323
6324 #define SORT_OUT_BUTTON(x) { \
6325 if (b##x) \
6326 { \
6327 alert_dialog[A_B##x].flags &= ~D_HIDDEN; \
6328 alert_dialog[A_B##x].key = c##x; \
6329 alert_dialog[A_B##x].dp = (void *)b##x; \
6330 len##x = gui_strlen(b##x); \
6331 b[buttons++] = A_B##x; \
6332 } \
6333 else \
6334 { \
6335 alert_dialog[A_B##x].flags |= D_HIDDEN; \
6336 len##x = 0; \
6337 } \
6338 }
6339
6340 if(title_font)
6341 {
6342 alert_dialog[0].dp2=title_font;
6343 }
6344
6345 alert_dialog[A_S1].dp = alert_dialog[A_S2].dp = alert_dialog[A_S3].dp =
6346 alert_dialog[A_B1].dp = alert_dialog[A_B2].dp = (void*)"";
6347
6348 if(s1)
6349 {
6350 alert_dialog[A_S1].dp = (void *)s1;
6351 maxlen = text_length(font, s1);
6352 }
6353
6354 if(s2)
6355 {
6356 alert_dialog[A_S2].dp = (void *)s2;
6357 len1 = text_length(font, s2);
6358
6359 if(len1 > maxlen)
6360 maxlen = len1;
6361 }
6362
6363 if(s3)
6364 {
6365 alert_dialog[A_S3].dp = (void *)s3;
6366 len1 = text_length(font, s3);
6367
6368 if(len1 > maxlen)
6369 maxlen = len1;
6370 }
6371
6372 SORT_OUT_BUTTON(1);
6373 SORT_OUT_BUTTON(2);
6374 SORT_OUT_BUTTON(3);
6375
6376 len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
6377
6378 if(len1*buttons > maxlen)
6379 maxlen = len1*buttons;
6380
6381 maxlen += avg_w*4;
6382 maxlen=zc_max(text_length(title_font?title_font:font,title)+29,maxlen);
6383 alert_dialog[0].w = maxlen;
6384 alert_dialog[A_S1].x = alert_dialog[A_S2].x = alert_dialog[A_S3].x =
6385 alert_dialog[0].x + maxlen/2;
6386
6387 alert_dialog[A_B1].w = alert_dialog[A_B2].w = alert_dialog[A_B3].w = len1;
6388
6389 alert_dialog[A_B1].x = alert_dialog[A_B2].x = alert_dialog[A_B3].x =
6390 alert_dialog[0].x + maxlen/2 - len1/2;
6391
6392 if(buttons == 3)
6393 {
6394 alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
6395 alert_dialog[b[2]].x = alert_dialog[0].x + maxlen/2 + len1/2 + avg_w;
6396 }
6397 else if(buttons == 2)
6398 {
6399 alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1 - avg_w;
6400 alert_dialog[b[1]].x = alert_dialog[0].x + maxlen/2 + avg_w;
6401 }
6402
6403 alert_dialog[0].h = avg_h*7 + 13 + yofs;
6404 alert_dialog[A_S1].y = alert_dialog[0].y + avg_h + yofs;
6405 alert_dialog[A_S2].y = alert_dialog[0].y + avg_h*2 + yofs;
6406 alert_dialog[A_S3].y = alert_dialog[0].y + avg_h*3 + yofs;
6407 alert_dialog[A_S1].h = alert_dialog[A_S2].h = alert_dialog[A_S3].h = avg_h;
6408
6409 alert_dialog[A_B1].y = alert_dialog[A_B2].y = alert_dialog[A_B3].y =
6410 alert_dialog[0].y + avg_h*5 + yofs;
6411
6412 alert_dialog[A_B1].h = alert_dialog[A_B2].h = alert_dialog[A_B3].h = avg_h+13;
6413
6414 alert_dialog[0].dp = (void *)title;
6415 alert_dialog[0].flags = (title) ? D_EXIT : 0;
6416
6417 jwin_center_dialog(alert_dialog);
6418 set_dialog_color(alert_dialog, scheme[jcTEXTFG], scheme[jcBOX]);
6419
6420 clear_keybuf();
6421
6422 do
6423 {
6424 rest(1);
6425 }
6426 while(gui_mouse_b());
6427
6428 large_dialog(alert_dialog);
6429 alert_dialog[0].d1 = 0;
6430
6431 c = do_zqdialog(alert_dialog, A_B1);
6432
6433 if(c == A_B1)
6434 return 1;
6435 else if(c == A_B2)
6436 return 2;
6437 else
6438 return 3;
6439 }
6440
6441 /* jwin_alert:
6442 * Displays a simple alert box, containing three lines of text (s1-s3),
6443 * and with either one or two buttons. The text for these buttons is passed
6444 * in b1 and b2 (b2 may be null), and the keyboard shortcuts in c1 and c2.
6445 * Returns 1 or 2 depending on which button was selected.
6446 */
6447 int32_t jwin_alert(const char *title, const char *s1, const char *s2, const char *s3, const char *b1, const char *b2, int32_t c1, int32_t c2, FONT *title_font)
6448 {
6449 int32_t ret;
6450
6451 ret = jwin_alert3(title, s1, s2, s3, b1, b2, NULL, c1, c2, 0, title_font);
6452
6453 if(ret > 2)
6454 ret = 2;
6455
6456 return ret;
6457 }
6458
6459 int32_t d_autotext_proc(int32_t msg, DIALOG *d, int32_t c)
6460 {
6461 ASSERT(d);
6462 ASSERT(d->dp);
6463 #define AUTOBUF_SIZE 8092
6464 static char auto_buf[AUTOBUF_SIZE] = {0};
6465 static int32_t auto_inds[50] = {0};
6466
6467
6468 FONT *oldfont = font;
6469
6470 if (d->dp2)
6471 font = (FONT*)d->dp2;
6472 switch(msg)
6473 {
6474 case MSG_START:
6475 {
6476 memset(auto_buf, 0, AUTOBUF_SIZE);
6477 memset(auto_inds, 0, 50);
6478 char* str = (char*)d->dp;
6479 int32_t len = strlen(str);
6480 int32_t pos = 0, curstrpos = 0, linecount = 1, lastWS = -1;
6481 BITMAP* dummy = create_bitmap_ex(8,8,8);
6482 for(int32_t q = 0; q < len; ++q)
6483 {
6484 switch(str[q])
6485 {
6486 case ' ': case '\t':
6487 lastWS = pos;
6488 break;
6489 case '\n': //Forced newline
6490 auto_inds[linecount++] = ++pos;
6491 curstrpos = pos;
6492 lastWS = -1;
6493 continue; //skip rest of for loop, go to next char
6494 }
6495 auto_buf[pos++] = str[q];
6496 if(gui_textout_ex(dummy,auto_buf+curstrpos,0,0,0,0,0) >= d->w) //too int32_t, wrap to lower line
6497 {
6498 if(lastWS<0)
6499 {
6500 auto_buf[pos-1] = 0;
6501 auto_inds[linecount++] = pos;
6502 curstrpos = pos;
6503 auto_buf[pos++] = str[q];
6504 }
6505 else
6506 {
6507 auto_buf[lastWS] = 0;
6508 auto_inds[linecount++] = lastWS+1;
6509 curstrpos = lastWS+1;
6510 if(gui_textout_ex(dummy,auto_buf+curstrpos,0,0,0,0,0) >= d->w) //STILL too int32_t?
6511 {
6512 auto_buf[pos-1] = 0;
6513 auto_inds[linecount++] = pos;
6514 curstrpos = pos;
6515 auto_buf[pos++] = str[q];
6516 }
6517 lastWS = -1;
6518 }
6519 }
6520 }
6521 destroy_bitmap(dummy);
6522 d->d2 = linecount;
6523 d->h = ((text_height(font) + d->d1) * linecount) - d->d1;
6524 }
6525 break;
6526
6527 case MSG_DRAW:
6528 {
6529 int32_t fg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
6530 int32_t linecount = d->d2;
6531
6532 int32_t yinc = text_height(font)+d->d1;
6533 int32_t y = d->y;
6534 for(int32_t q = 0; q < linecount; ++q)
6535 {
6536 gui_textout_ex(screen, auto_buf+auto_inds[q], d->x, y, fg, d->bg, true);
6537 y += yinc;
6538 }
6539 }
6540 break;
6541 }
6542 font = oldfont;
6543 return D_O_K;
6544 }
6545
6546 static DIALOG alert2_dialog[] =
6547 {
6548 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
6549 { jwin_win_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6550 { d_autotext_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6551 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6552 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6553 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6554 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6555 };
6556
6557 #define A2_S1 1
6558 #define A2_B1 2
6559 #define A2_B2 3
6560 #define A2_B3 4
6561
6562 /* jwin_auto_alert3:
6563 * Displays a simple alert box, containing one line of text, auto-split
6564 * across lines using 'lenlim' and 'vspace,
6565 * and with either one, two, or three buttons. The text for these buttons
6566 * is passed in b1, b2, and b3 (NULL for buttons which are not used), and
6567 * the keyboard shortcuts in c1 and c2. Returns 1, 2, or 3 depending on
6568 * which button was selected.
6569 */
6570 int32_t jwin_auto_alert3(const char *title, const char *s1, int32_t lenlim, int32_t vspace, const char *b1, const char *b2, const char *b3, int32_t c1, int32_t c2, int32_t c3, FONT *title_font)
6571 {
6572 int32_t maxlen = 0;
6573 int32_t len1, len2, len3;
6574 int32_t avg_w = text_length(font, " ");
6575 int32_t avg_h = text_height(font)+1;
6576 int32_t buttons = 0;
6577 int32_t yofs = (title ? 22 : 0);
6578 int32_t b[3];
6579 int32_t c;
6580
6581 #define SORT_OUT_AUTOBUTTON(x) { \
6582 if (b##x) \
6583 { \
6584 alert2_dialog[A2_B##x].flags &= ~D_HIDDEN; \
6585 alert2_dialog[A2_B##x].key = c##x; \
6586 alert2_dialog[A2_B##x].dp = (void *)b##x; \
6587 len##x = gui_strlen(b##x); \
6588 b[buttons++] = A2_B##x; \
6589 } \
6590 else \
6591 { \
6592 alert2_dialog[A2_B##x].flags |= D_HIDDEN; \
6593 len##x = 0; \
6594 } \
6595 }
6596
6597 if(title_font)
6598 {
6599 alert2_dialog[0].dp2=title_font;
6600 }
6601
6602 alert2_dialog[A2_S1].dp = alert2_dialog[A2_B1].dp = alert2_dialog[A2_B2].dp = (void*)"";
6603
6604 if(s1)
6605 {
6606 alert2_dialog[A2_S1].dp = (void *)s1;
6607 maxlen = lenlim;
6608 }
6609
6610 SORT_OUT_AUTOBUTTON(1);
6611 SORT_OUT_AUTOBUTTON(2);
6612 SORT_OUT_AUTOBUTTON(3);
6613
6614 len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
6615
6616 if(len1*buttons > maxlen)
6617 maxlen = len1*buttons;
6618
6619 maxlen += avg_w*4;
6620 maxlen=zc_max(text_length(title_font?title_font:font,title)+29,maxlen);
6621
6622 alert2_dialog[A2_S1].x = alert2_dialog[0].x + maxlen/2;
6623 alert2_dialog[A2_S1].y = alert2_dialog[0].y + avg_h + yofs;
6624 alert2_dialog[A2_S1].w = lenlim;
6625 alert2_dialog[A2_S1].d1 = vspace;
6626
6627 large_dialog(alert2_dialog);
6628 alert2_dialog[0].d1 = 0;
6629
6630 object_message(&alert2_dialog[A2_S1], MSG_START, 0); //calculate height
6631
6632 alert2_dialog[A2_S1].x = alert2_dialog[0].x + maxlen/2;
6633 alert2_dialog[A2_S1].y = alert2_dialog[0].y + avg_h + yofs;
6634 alert2_dialog[A2_S1].w = lenlim;
6635 alert2_dialog[A2_S1].d1 = vspace;
6636
6637 alert2_dialog[A2_B1].w = alert2_dialog[A2_B2].w = alert2_dialog[A2_B3].w = len1;
6638
6639 alert2_dialog[A2_B1].x = alert2_dialog[A2_B2].x = alert2_dialog[A2_B3].x =
6640 alert2_dialog[0].x + maxlen/2 - len1/2;
6641
6642 if(buttons == 3)
6643 {
6644 alert2_dialog[b[0]].x = alert2_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
6645 alert2_dialog[b[2]].x = alert2_dialog[0].x + maxlen/2 + len1/2 + avg_w;
6646 }
6647 else if(buttons == 2)
6648 {
6649 alert2_dialog[b[0]].x = alert2_dialog[0].x + maxlen/2 - len1 - avg_w;
6650 alert2_dialog[b[1]].x = alert2_dialog[0].x + maxlen/2 + avg_w;
6651 }
6652
6653 alert2_dialog[0].w = maxlen;
6654 alert2_dialog[0].h = avg_h*4 + yofs + alert2_dialog[A2_S1].h + 13;
6655 alert2_dialog[A2_B1].y = alert2_dialog[A2_B2].y = alert2_dialog[A2_B3].y =
6656 alert2_dialog[0].y + avg_h*2 + yofs + alert2_dialog[A2_S1].h;
6657
6658 alert2_dialog[A2_B1].h = alert2_dialog[A2_B2].h = alert2_dialog[A2_B3].h = avg_h+13;
6659
6660 alert2_dialog[0].dp = (void *)title;
6661 alert2_dialog[0].flags = (title) ? D_EXIT : 0;
6662
6663 jwin_center_dialog(alert2_dialog);
6664 set_dialog_color(alert2_dialog, scheme[jcTEXTFG], scheme[jcBOX]);
6665
6666 clear_keybuf();
6667
6668 do
6669 {
6670 rest(1);
6671 }
6672 while(gui_mouse_b());
6673
6674 large_dialog(alert2_dialog);
6675 alert2_dialog[0].d1 = 0;
6676
6677 c = do_zqdialog(alert2_dialog, A2_B1);
6678
6679 if(c == A2_B1)
6680 return 1;
6681 else if(c == A2_B2)
6682 return 2;
6683 else
6684 return 3;
6685 }
6686
6687 int32_t jwin_auto_alert(const char *title, const char *s1, int32_t lenlim, int32_t vspace, const char *b1, const char *b2, int32_t c1, int32_t c2, FONT *title_font)
6688 {
6689 int32_t ret;
6690
6691 ret = jwin_auto_alert3(title, s1, lenlim, vspace, b1, b2, NULL, c1, c2, 0, title_font);
6692
6693 if(ret > 2)
6694 ret = 2;
6695
6696 return ret;
6697 }
6698
6699 int32_t last_droplist_sel = -1;
6700 static int32_t d_dropcancel_proc(int32_t msg,DIALOG *d,int32_t c)
6701 {
6702 //these are here to bypass compiler warnings about unused arguments
6703 d=d;
6704 c=c;
6705
6706 if(msg==MSG_CLICK || msg==MSG_DCLICK)
6707 return D_CLOSE;
6708
6709 return D_O_K;
6710 }
6711
6712 static DIALOG droplist_dlg[] =
6713 {
6714 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3)*/
6715 { d_dropcancel_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6716 { d_list_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6717 { d_keyboard_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_ESC, (void*)close_dlg, NULL, NULL },
6718 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6719 };
6720
6721 static int32_t droplist(DIALOG *d)
6722 {
6723 ListData *data = (ListData *)d->dp;
6724 int32_t d1 = d->d1;
6725 int32_t listsize, x, y, w, h, max_w;
6726 auto oz = gui_mouse_z();
6727
6728 data->listFunc(-1, &listsize);
6729 y = d->y + d->h;
6730 h = zc_min(abc_patternmatch ? listsize+1 : listsize,8) * text_height(*data->font) + 8;
6731
6732 if(y+h >= zq_screen_h)
6733 {
6734 y = d->y - h;
6735 }
6736
6737 x = d->x;
6738 w = d->w;
6739 max_w = zc_max(d->x+d->w, zq_screen_w-d->x);
6740
6741 for(int32_t i=0; i<listsize; ++i)
6742 {
6743 w=zc_min(max_w,zc_max(w,text_length(*data->font,data->listFunc(i, NULL))+39));
6744 }
6745
6746 if(x+w >= zq_screen_w)
6747 {
6748 x=zq_screen_w-w;
6749 }
6750
6751 droplist_dlg[1] = *d;
6752 droplist_dlg[1].proc = &jwin_abclist_proc;
6753 droplist_dlg[1].flags = D_EXIT + D_USER;
6754 droplist_dlg[1].x = x;
6755 droplist_dlg[1].y = y;
6756 droplist_dlg[1].w = w;
6757 droplist_dlg[1].h = h;
6758 droplist_dlg[1].d2 = listsize<=8 ? 0 : zc_max(d1-3,0);
6759
6760 // cancel
6761 droplist_dlg[0].x = 0;
6762 droplist_dlg[0].y = 0;
6763 droplist_dlg[0].w = zq_screen_w;
6764 droplist_dlg[0].h = zq_screen_h;
6765
6766 if(do_zq_subdialog(droplist_dlg,1)==1)
6767 {
6768 position_mouse_z(oz);
6769 return droplist_dlg[1].d1;
6770 }
6771
6772 position_mouse_z(oz);
6773 return d1;
6774 }
6775
6776 /* jwin_droplist_proc:
6777 * A drop list...
6778 */
6779 int32_t jwin_droplist_proc(int32_t msg,DIALOG *d,int32_t c)
6780 {
6781 int32_t ret;
6782 int32_t down=0, last_draw=0;
6783 int32_t d1;
6784
6785 switch(msg)
6786 {
6787 case MSG_CLICK:
6788 if(mouse_in_rect(d->x+d->w-18,d->y+2,16,d->h))
6789 goto dropit;
6790
6791 break;
6792
6793 case MSG_KEY:
6794 goto dropit;
6795 break;
6796 }
6797
6798 d1 = d->d1;
6799 ret = jwin_list_proc(msg,d,c);
6800
6801 if(d->d1!=d->d2)
6802 {
6803 d->d1=d->d2;
6804 jwin_droplist_proc(MSG_DRAW, d, 0);
6805 }
6806
6807 if(d1 != d->d1)
6808 {
6809 GUI_EVENT(d, geCHANGE_SELECTION);
6810 if(d->flags&D_EXIT)
6811 ret |= D_CLOSE;
6812 }
6813
6814 if(msg == MSG_DRAW)
6815 {
6816 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, 0);
6817 }
6818
6819 return ret;
6820
6821 dropit:
6822 last_draw = 0;
6823
6824 while(gui_mouse_b())
6825 {
6826 down = mouse_in_rect(d->x+d->w-18,d->y+2,16,d->h);
6827
6828 if(down!=last_draw)
6829 {
6830 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, down*3);
6831 last_draw = down;
6832 update_hw_screen();
6833 }
6834
6835 clear_keybuf();
6836 rest(1);
6837 }
6838
6839 if(!down)
6840 {
6841 return D_O_K;
6842 }
6843
6844 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, 0);
6845
6846 d1 = d->d1;
6847 d->d2 = d->d1 = droplist(d);
6848
6849 object_message(d, MSG_DRAW, 0);
6850
6851 while(gui_mouse_b())
6852 {
6853 clear_keybuf();
6854 rest(1);
6855 update_hw_screen();
6856 }
6857
6858 if(d1!=d->d1)
6859 GUI_EVENT(d, geCHANGE_SELECTION);
6860
6861 return ((d1 != d->d1) && (d->flags&D_EXIT)) ? D_CLOSE : D_O_K;
6862 }
6863
6864
6865 int32_t jwin_abclist_proc(int32_t msg,DIALOG *d,int32_t c)
6866 {
6867 ListData *data = (ListData *)d->dp;
6868 if(msg == MSG_START) wipe_abc_keypresses();
6869
6870 if(msg == MSG_CHAR && (key_shifts&KB_CTRL_FLAG))
6871 return D_O_K;
6872
6873 if(abc_patternmatch) // Search style pattern match.
6874 {
6875 if(msg==MSG_CHAR && ((c&0xFF) > 31) && ((c&0xFF) < 127)) //(isalpha(c&0xFF) || isdigit(c&0xFF)))
6876 {
6877 int32_t max,dummy,h;
6878
6879 h = ((d->h-3) / text_height(*data->font))-1;
6880 if ( isalpha(c&0xFF) ) c = toupper(c&0xFF);
6881 for ( int32_t q = 0; q < 1023; ++q )
6882 {
6883 if ( !(abc_keypresses[q]) )
6884 {
6885 abc_keypresses[q] = (char)c;
6886 break;
6887 }
6888 }
6889 data->listFunc(-1, &max);
6890
6891 int32_t cur = d->d1;
6892 int32_t charpos = 0; int32_t listpos = 0; int32_t lastmatch = -1;
6893 char tmp[1024] = { 0 };
6894 char lsttmp[1024] = { 0 };
6895 int32_t lastmatches[32768] = {0};
6896 for ( int32_t a = 0; a < 32768; ++a ) lastmatches[a] = -1;
6897 int32_t lmindx = 0;
6898
6899 bool foundmatch = false;
6900 bool numsearch = true;
6901 for ( int32_t q = 0; q < 1023; ++q )
6902 {
6903 if(!abc_keypresses[q]) break;
6904 if(!isdigit(abc_keypresses[q]))
6905 {
6906 if(q == 0 && abc_keypresses[q] == '-')
6907 continue;
6908 numsearch = false;
6909 break;
6910 }
6911 }
6912 if(numsearch) //Indexed search, first
6913 {
6914 int32_t num = atoi(abc_keypresses);
6915 //Find a different indexing type in the strings?
6916 if(!foundmatch)
6917 {
6918 char buf[16];
6919 if(num < 0) sprintf(buf, "(%04d)", num);
6920 else sprintf(buf, "(%03d)", num);
6921 std::string cmp = buf;
6922 for(int32_t listpos = 0; listpos < max; ++listpos)
6923 {
6924 std::string str((data->listFunc(listpos,&dummy)));
6925 size_t trimpos = str.find_last_not_of("-(0123456789)");
6926 if(trimpos != std::string::npos) ++trimpos;
6927 str.erase(0, trimpos);
6928 if(cmp == str)
6929 {
6930 d->d1 = listpos;
6931 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
6932 foundmatch = true;
6933 break;
6934 }
6935 }
6936 }
6937 //Search for match with first number in string?
6938 if(!foundmatch)
6939 {
6940 auto buf = fmt::format("{}", num);
6941 for(int32_t listpos = 0; listpos < max; ++listpos)
6942 {
6943 std::string str((data->listFunc(listpos,&dummy)));
6944 size_t pos1 = -1;
6945 do
6946 {
6947 pos1 = str.find_first_of("-0123456789", pos1+1);
6948 } while(pos1 != string::npos && str[pos1] == '-' && pos1+1 < str.size() && !isdigit(str[pos1+1]));
6949 if(pos1 == string::npos)
6950 continue;
6951 size_t pos2 = str.find_first_not_of("-0123456789", pos1);
6952 if(pos2 == string::npos)
6953 continue;
6954 str = str.substr(pos1,pos2-pos1);
6955 if(buf == str)
6956 {
6957 d->d1 = listpos;
6958 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
6959 foundmatch = true;
6960 break;
6961 }
6962 }
6963 }
6964 }
6965 if(!foundmatch)
6966 {
6967 strcpy(tmp, abc_keypresses);
6968 for ( int32_t listpos = 0; listpos < max; ++listpos )
6969 {
6970 memset(lsttmp, 0, 1024);
6971 strcpy(lsttmp, ((data->listFunc(listpos,&dummy))));
6972
6973 if ( !(strnicmp(lsttmp, tmp, strlen(tmp))))
6974 {
6975 d->d1 = listpos;
6976 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
6977 foundmatch = true;
6978 break;
6979 }
6980 }
6981 }
6982 if(foundmatch)
6983 GUI_EVENT(d, geCHANGE_SELECTION);
6984 d->flags |= D_DIRTY;
6985 if ( gui_mouse_b() ) wipe_abc_keypresses();
6986 return foundmatch ? D_USED_CHAR : D_O_K;
6987 }
6988 else if(msg==MSG_CHAR && ( (c&0xFF) == 8) )//backspace
6989 {
6990 for ( int32_t q = 1023; q >= 0; --q )
6991 {
6992 if ( abc_keypresses[q] )
6993 {
6994 d->flags |= D_DIRTY;
6995 abc_keypresses[q] = '\0'; break;
6996 }
6997 }
6998 return D_USED_CHAR;
6999 }
7000 if ( gui_mouse_b() ) { wipe_abc_keypresses(); }
7001 }
7002 else // Windows Explorer style jumping
7003 {
7004 if(msg==MSG_CHAR && (isalpha(c&0xFF) || isdigit(c&0xFF)))
7005 {
7006 int32_t max,dummy,h,i;
7007
7008 h = (d->h-3) / text_height(*data->font);
7009 c = toupper(c&0xFF);
7010
7011 data->listFunc(-1, &max);
7012
7013 int32_t cur = d->d1;
7014 bool foundmatch = false;
7015 for(i=cur+1; (cur ? (i != cur) : (cur < max)); ++i) //don't infinite loop this.
7016 {
7017 if(i>=max) i=0;
7018 if(toupper((data->listFunc(i,&dummy))[0]) == c)
7019 {
7020 d->d1 = i;
7021 d->d2 = zc_max(zc_min(i-(h>>1), max-h), 0);
7022 foundmatch = true;
7023 break;
7024 }
7025 }
7026
7027 d->flags |= D_DIRTY;
7028 return foundmatch ? D_USED_CHAR : D_O_K;
7029 }
7030 }
7031 if ( gui_mouse_b() ) { wipe_abc_keypresses(); }
7032 return ((abc_patternmatch) ? jwin_do_abclist_proc(msg,d,c) : jwin_list_proc(msg,d,c));
7033 }
7034
7035 int32_t jwin_checkfont_proc(int32_t msg, DIALOG *d, int32_t c)
7036 {
7037
7038 FONT *oldfont = font;
7039
7040 if(d->dp2)
7041 {
7042 font = (FONT *)d->dp2;
7043 }
7044
7045 int32_t rval = jwin_check_proc(msg, d, c);
7046 font = oldfont;
7047 return rval;
7048 }
7049
7050 /* jwin_check_proc:
7051 * Who needs C++ after all? This is derived from d_button_proc,
7052 * but overrides the drawing routine to provide a check box.
7053 */
7054 int32_t jwin_check_proc(int32_t msg, DIALOG *d, int32_t c)
7055 {
7056 //these are here to bypass compiler warnings about unused arguments
7057 c=c;
7058 int32_t x;
7059 int32_t bx=0, tl=0;
7060 int32_t tx=d->x;
7061 ASSERT(d);
7062
7063 switch(msg)
7064 {
7065 case MSG_DRAW:
7066 x = d->x;
7067
7068 if(!(d->d1))
7069 {
7070 if(d->dp)
7071 {
7072 if(d->flags & D_DISABLED)
7073 {
7074 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7075 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7076 bx=tl+text_height(font)/2;
7077 }
7078 else
7079 {
7080 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7081 bx=tl+text_height(font)/2;
7082 }
7083 }
7084 }
7085
7086 jwin_draw_frame(screen, x+bx, d->y, d->h, d->h, FR_DEEP);
7087
7088 if(!(d->flags & D_DISABLED))
7089 {
7090 rectfill(screen, x+bx+2, d->y+2, x+bx+d->h-3, d->y+d->h-3, scheme[jcTEXTBG]);
7091 }
7092
7093 if(d->d1)
7094 {
7095 tx=x+bx+d->h-1+(text_height(font)/2);
7096
7097 if(d->dp)
7098 {
7099 if(d->flags & D_DISABLED)
7100 {
7101 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7102 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7103 }
7104 else
7105 {
7106 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7107 }
7108 }
7109 }
7110
7111 if(d->flags & D_SELECTED)
7112 {
7113 line(screen, x+bx+2, d->y+2, x+bx+d->h-3, d->y+d->h-3, scheme[jcTEXTFG]);
7114 line(screen, x+bx+2, d->y+d->h-3, x+bx+d->h-3, d->y+2, scheme[jcTEXTFG]);
7115 }
7116
7117 d->w=int32_t(text_height(font)*1.5);
7118
7119 if(d->dp)
7120 {
7121 // dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+d->h-1, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7122 dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+(text_height(font)), (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7123 d->w+=tl+1;
7124 }
7125
7126 return D_O_K;
7127 break;
7128 }
7129
7130 return d_jwinbutton_proc(msg, d, 0);
7131 }
7132
7133 int32_t new_check_proc(int32_t msg, DIALOG *d, int32_t)
7134 {
7135 int32_t bx=0, tl=0;
7136 ASSERT(d);
7137
7138 FONT *oldfont = font;
7139 uint8_t* str = (uint8_t*)d->dp;
7140 bool has_text = str && str[0];
7141 if(d->dp2)
7142 {
7143 font = (FONT *)d->dp2;
7144 }
7145 switch(msg)
7146 {
7147 case MSG_DRAW:
7148 {
7149 const int box_spacing = 4;
7150 int32_t tx = 2, ty = 2, tx2 = 2;
7151 int fh = text_height(font);
7152 auto txt_y = ty+(d->h-fh)/2;
7153 BITMAP* tmp = create_bitmap_ex(8, d->w+4, d->h+4);
7154 clear_bitmap(tmp);
7155 set_clip_rect(tmp, tx, ty, tmp->w-tx, tmp->h-ty);
7156 if(!(d->d1))
7157 {
7158 if(has_text)
7159 {
7160 if(d->flags & D_DISABLED)
7161 {
7162 gui_textout_ln(tmp, str, tx+1, txt_y+1, scheme[jcLIGHT], scheme[jcBOX], 0);
7163 tl=gui_textout_ln(tmp, str, tx, txt_y, scheme[jcDISABLED_FG], -1, 0);
7164 bx=tl+box_spacing;
7165 }
7166 else
7167 {
7168 tl=gui_textout_ln(tmp, str, tx, txt_y, scheme[jcBOXFG], scheme[jcBOX], 0);
7169 bx=tl+box_spacing;
7170 }
7171 }
7172 }
7173
7174 jwin_draw_frame(tmp, tx+bx, ty, d->h, d->h, FR_DEEP);
7175
7176 if(!(d->flags & D_DISABLED))
7177 {
7178 rectfill(tmp, tx+bx+2, ty+2, tx+bx+d->h-3, ty+d->h-3, scheme[jcTEXTBG]);
7179 }
7180
7181 if(d->d1)
7182 {
7183 tx2=tx+bx+d->h-1+box_spacing;
7184
7185 if(has_text)
7186 {
7187 if(d->flags & D_DISABLED)
7188 {
7189 gui_textout_ln(tmp, str, tx2+1, txt_y+1, scheme[jcLIGHT], scheme[jcBOX], 0);
7190 tl=gui_textout_ln(tmp, str, tx2, txt_y, scheme[jcDISABLED_FG], -1, 0);
7191 }
7192 else
7193 {
7194 tl=gui_textout_ln(tmp, str, tx2, txt_y, scheme[jcBOXFG], scheme[jcBOX], 0);
7195 }
7196 }
7197 }
7198
7199 if(d->flags & D_SELECTED)
7200 {
7201 line(tmp, tx+bx+2, ty+2, tx+bx+d->h-3, ty+d->h-3, scheme[jcTEXTFG]);
7202 line(tmp, tx+bx+2, ty+d->h-3, tx+bx+d->h-3, ty+2, scheme[jcTEXTFG]);
7203 }
7204
7205 set_clip_rect(tmp, 0, 0, tmp->w, tmp->h);
7206 if(has_text)
7207 {
7208 dotted_rect(tmp, tx2-1, txt_y-1, tx2+tl, txt_y+fh, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7209 }
7210
7211 masked_blit(tmp, screen, 0, 0, d->x-tx, d->y-ty, d->w+tx+tx, d->h+ty+ty);
7212 break;
7213 }
7214 }
7215
7216 int32_t rval = D_O_K;
7217 if(msg != MSG_DRAW)
7218 rval = d_jwinbutton_proc(msg, d, 0);
7219 font = oldfont;
7220 return rval;
7221 }
7222
7223 int32_t jwin_radiofont_proc(int32_t msg, DIALOG *d, int32_t c)
7224 {
7225 FONT *oldfont = font;
7226
7227 if(d->dp2)
7228 {
7229 font = (FONT *)d->dp2;
7230 }
7231
7232 int32_t rval = jwin_radio_proc(msg, d, c);
7233 font = oldfont;
7234 return rval;
7235 }
7236
7237 /* jwin_radio_proc:
7238 * GUI procedure for radio buttons.
7239 * Parameters: d1-button group number; d2-button style (0=circle,1=square);
7240 * dp-text to appear as label to the right of the button.
7241 */
7242 int32_t jwin_radio_proc(int32_t msg, DIALOG *d, int32_t c)
7243 {
7244 int32_t x, center, r, ret, tl=0, tx;
7245 ASSERT(d);
7246
7247 switch(msg)
7248 {
7249 case MSG_DRAW:
7250 // tx=d->x+d->h-1+text_height(font);
7251 tx=d->x+int32_t(text_height(font)*1.5);
7252
7253 if(d->dp)
7254 {
7255 if(d->flags & D_DISABLED)
7256 {
7257 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7258 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7259 }
7260 else
7261 {
7262 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7263 }
7264 }
7265
7266 x = d->x;
7267 r = d->h/2;
7268
7269 center = x+r;
7270 rectfill(screen, x, d->y, x+d->h-1, d->y+d->h-1, scheme[jcBOX]);
7271
7272 switch(d->d2)
7273 {
7274 case 1:
7275 jwin_draw_frame(screen, x, d->y, d->h, d->h, FR_DEEP);
7276
7277 if(!(d->flags & D_DISABLED))
7278 {
7279 rectfill(screen, x+2, d->y+2, x+d->h-3, d->y+d->h-3, scheme[jcLIGHT]);
7280 }
7281
7282 if(d->flags & D_SELECTED)
7283 {
7284 rectfill(screen, x+r/2, d->y+r/2, x+d->h-1-r/2, d->y+d->h-1-r/2, scheme[jcDARK]);
7285 //line(screen, x+2, d->y+2, x+d->h-3, d->y+d->h-3, scheme[jcDARK]);
7286 //line(screen, x+2, d->y+d->h-3, x+d->h-3, d->y+2, scheme[jcDARK]);
7287 }
7288
7289 break;
7290
7291 default:
7292 circlefill(screen, center, d->y+r, r, scheme[jcTEXTBG]);
7293 arc(screen, center, d->y+r, itofix(32), itofix(160), r, vc(0));
7294 circlefill(screen, center, d->y+r, r-1, scheme[jcTEXTBG]);
7295 arc(screen, center, d->y+r, itofix(32), itofix(160), r-1, vc(0));
7296 circlefill(screen, center, d->y+r, r-2, (d->flags & D_DISABLED)?scheme[jcDISABLED_BG]:scheme[jcTEXTBG]);
7297
7298 if(d->flags & D_SELECTED)
7299 {
7300 circlefill(screen, center, d->y+r, r-3, scheme[jcTEXTFG]);
7301 }
7302
7303 break;
7304 }
7305
7306 if(d->dp)
7307 {
7308 // dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+d->h-1, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7309 dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+(text_height(font)), (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7310 d->w=tl+int32_t(text_height(font)*1.5)+1;
7311 }
7312
7313 return D_O_K;
7314
7315 case MSG_KEY:
7316 case MSG_CLICK:
7317 if(d->flags & D_SELECTED)
7318 {
7319 return D_O_K;
7320 }
7321
7322 break;
7323
7324 case MSG_RADIO:
7325 if((c == d->d1) && (d->flags & D_SELECTED))
7326 {
7327 d->flags &= ~D_SELECTED;
7328 object_message(d, MSG_DRAW, 0);
7329 }
7330
7331 break;
7332 }
7333
7334 ret = d_jwinbutton_proc(msg, d, 0);
7335
7336 if(((msg==MSG_KEY) || (msg==MSG_CLICK)) && (d->flags & D_SELECTED) && (!(d->flags & D_EXIT)))
7337 {
7338 d->flags &= ~D_SELECTED;
7339 broadcast_dialog_message(MSG_RADIO, d->d1);
7340 d->flags |= D_SELECTED;
7341 GUI_EVENT(d, geRADIO);
7342 }
7343
7344 return ret;
7345 }
7346
7347
7348 /* 1.5k lookup table for color matching */
7349 uint32_t col_diff[3*128];
7350
7351 /* bestfit_init:
7352 * Color matching is done with weighted squares, which are much faster
7353 * if we pregenerate a little lookup table...
7354 */
7355 70 void bestfit_init(void)
7356 {
7357 int32_t i;
7358
7359 70 col_diff[0] = col_diff[128] = col_diff[256] = 0;
7360
7361
2/2
✓ Branch 0 taken 4410 times.
✓ Branch 1 taken 70 times.
4480 for(i=1; i<64; i++)
7362 {
7363 4410 int32_t k = i * i;
7364 4410 col_diff[0 +i] = col_diff[0 +128-i] = k * (59 * 59);
7365 4410 col_diff[128+i] = col_diff[128+128-i] = k * (30 * 30);
7366 4410 col_diff[256+i] = col_diff[256+128-i] = k * (11 * 11);
7367 4410 }
7368 70 }
7369
7370
7371
7372 /* bestfit_color:
7373 * Searches a palette for the color closest to the requested R, G, B value.
7374 */
7375 int32_t bestfit_color_range(AL_CONST PALETTE pal, int32_t r, int32_t g, int32_t b, uint8_t start, uint8_t end)
7376 {
7377 int32_t i, coldiff, lowest, bestfit;
7378
7379 if(col_diff[1] == 0)
7380 bestfit_init();
7381
7382 bestfit = start;
7383 lowest = INT_MAX;
7384
7385 i = start;
7386
7387 while(i<PAL_SIZE&&i<=end)
7388 {
7389 AL_CONST RGB *rgb = &pal[i];
7390 coldiff = (col_diff + 0) [(rgb->g - g) & 0x7F ];
7391
7392 if(coldiff < lowest)
7393 {
7394 coldiff += (col_diff + 128) [(rgb->r - r) & 0x7F ];
7395
7396 if(coldiff < lowest)
7397 {
7398 coldiff += (col_diff + 256) [(rgb->b - b) & 0x7F ];
7399
7400 if(coldiff < lowest)
7401 {
7402 bestfit = rgb - pal; /* faster than `bestfit = i;' */
7403
7404 if(coldiff == 0)
7405 {
7406 return bestfit;
7407 }
7408
7409 lowest = coldiff;
7410 }
7411 }
7412 }
7413
7414 i++;
7415 }
7416
7417 return bestfit;
7418 }
7419
7420
7421 /* makecol8:
7422 * Converts R, G, and B values (ranging 0-255) to an 8 bit paletted color.
7423 * If the global rgb_map table is initialised, it uses that, otherwise
7424 * it searches through the current palette to find the best match.
7425 */
7426 int32_t makecol8_map(int32_t r, int32_t g, int32_t b, RGB_MAP *table)
7427 {
7428 return table->data[r>>3][g>>3][b>>3];
7429 }
7430
7431
7432 /* create_rgb_table:
7433 * Fills an RGB_MAP lookup table with conversion data for the specified
7434 * palette. This is the faster version by Jan Hubicka.
7435 *
7436 * Uses alg. similar to floodfill - it adds one seed per every color in
7437 * palette to its best position. Then areas around seed are filled by
7438 * same color because it is best approximation for them, and then areas
7439 * about them etc...
7440 *
7441 * It does just about 80000 tests for distances and this is about 100
7442 * times better than normal 256*32000 tests so the calculation time
7443 * is now less than one second at all computers I tested.
7444 */
7445 8161 void create_rgb_table_range(RGB_MAP *table, AL_CONST PALETTE pal_8bit, uint8_t start, uint8_t end, void (*callback)(int32_t pos))
7446 {
7447 #define UNUSED 65535
7448 #define LAST 65532
7449
7450 // Allegro has been modified to use an 8 bit palette, but this method and RGB_MAP still use 6 bit.
7451 PALETTE pal;
7452
2/2
✓ Branch 0 taken 2089216 times.
✓ Branch 1 taken 8161 times.
2097377 for (int i = 0; i < 256; i++)
7453 {
7454 2089216 pal[i] = pal_8bit[i];
7455 2089216 pal[i].r /= 4;
7456 2089216 pal[i].g /= 4;
7457 2089216 pal[i].b /= 4;
7458 2089216 }
7459
7460 /* macro add adds to single linked list */
7461 #define add(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
7462 (first != LAST ? (next[last] = (i)) : (first = (i))), \
7463 (last = (i))) : 0)
7464
7465 /* same but w/o checking for first element */
7466 #define add1(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
7467 next[last] = (i), \
7468 (last = (i))) : 0)
7469
7470 /* calculates distance between two colors */
7471 #define dist(a1, a2, a3, b1, b2, b3) \
7472 (col_diff[ ((a2) - (b2)) & 0x7F] + \
7473 (col_diff + 128)[((a1) - (b1)) & 0x7F] + \
7474 (col_diff + 256)[((a3) - (b3)) & 0x7F])
7475
7476 /* converts r,g,b to position in array and back */
7477 #define pos(r, g, b) \
7478 (((r) / 2) * 32 * 32 + ((g) / 2) * 32 + ((b) / 2))
7479
7480 #define depos(pal, r, g, b) \
7481 ((b) = ((pal) & 31) * 2, \
7482 (g) = (((pal) >> 5) & 31) * 2, \
7483 (r) = (((pal) >> 10) & 31) * 2)
7484
7485 /* is current color better than pal1? */
7486 #define better(r1, g1, b1, pal1) \
7487 (((int32_t)dist((r1), (g1), (b1), \
7488 (pal1).r, (pal1).g, (pal1).b)) > (int32_t)dist2)
7489
7490 /* checking of position */
7491 #define dopos(rp, gp, bp, ts) \
7492 if ((rp > -1 || r > 0) && (rp < 1 || r < 61) && \
7493 (gp > -1 || g > 0) && (gp < 1 || g < 61) && \
7494 (bp > -1 || b > 0) && (bp < 1 || b < 61)) { \
7495 i = first + rp * 32 * 32 + gp * 32 + bp; \
7496 if (!data[i]) { \
7497 data[i] = val; \
7498 add1(i); \
7499 } \
7500 else if ((ts) && (data[i] != val)) { \
7501 dist2 = (rp ? (col_diff+128)[(r+2*rp-pal[val].r) & 0x7F] : r2) + \
7502 (gp ? (col_diff )[(g+2*gp-pal[val].g) & 0x7F] : g2) + \
7503 (bp ? (col_diff+256)[(b+2*bp-pal[val].b) & 0x7F] : b2); \
7504 if (better((r+2*rp), (g+2*gp), (b+2*bp), pal[data[i]])) { \
7505 data[i] = val; \
7506 add1(i); \
7507 } \
7508 } \
7509 }
7510
7511 int32_t i, curr, r, g, b, val, dist2;
7512 uint32_t r2, g2, b2;
7513 uint16_t next[32*32*32];
7514 uint8_t *data;
7515 8161 int32_t first = LAST;
7516 8161 int32_t last = LAST;
7517 8161 int32_t count = 0;
7518 8161 int32_t cbcount = 0;
7519
7520 #define AVERAGE_COUNT 18000
7521
7522
2/2
✓ Branch 0 taken 8100 times.
✓ Branch 1 taken 61 times.
8161 if(col_diff[1] == 0)
7523 61 bestfit_init();
7524
7525 8161 memset(next, 255, sizeof(next));
7526 8161 memset(table->data, 0, sizeof(char)*32*32*32);
7527
7528 8161 data = (uint8_t *)table->data;
7529
7530 /* add starting seeds for floodfill */
7531
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 269313 times.
✓ Branch 2 taken 261152 times.
✓ Branch 3 taken 8161 times.
269313 for(i=start; i<PAL_SIZE&&i<=end; i++)
7532 {
7533 261152 curr = pos(pal[i].r, pal[i].g, pal[i].b);
7534
7535
2/2
✓ Branch 0 taken 93585 times.
✓ Branch 1 taken 167567 times.
261152 if(next[curr] == UNUSED)
7536 {
7537 167567 data[curr] = i;
7538
3/4
✓ Branch 0 taken 167567 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 159406 times.
✓ Branch 3 taken 8161 times.
167567 add(curr);
7539 167567 }
7540 261152 }
7541
7542 /* main floodfill: two versions of loop for faster growing in blue axis */
7543
2/2
✓ Branch 0 taken 8161 times.
✓ Branch 1 taken 155633776 times.
155641937 while(first < LAST)
7544 {
7545 155633776 depos(first, r, g, b);
7546
7547 /* calculate distance of current color */
7548 155633776 val = data[first];
7549 155633776 r2 = (col_diff+128)[((pal[val].r)-(r)) & 0x7F];
7550 155633776 g2 = (col_diff)[((pal[val].g)-(g)) & 0x7F];
7551 155633776 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7552
7553 /* try to grow to all directions */
7554 #ifdef _MSC_VER
7555 #pragma warning(disable:4127)
7556 #endif
7557
11/12
✓ Branch 0 taken 4193476 times.
✓ Branch 1 taken 151440300 times.
✓ Branch 2 taken 138087429 times.
✓ Branch 3 taken 13352871 times.
✓ Branch 4 taken 13352871 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 126986689 times.
✓ Branch 7 taken 11100740 times.
✓ Branch 8 taken 2984469 times.
✓ Branch 9 taken 8116271 times.
✓ Branch 10 taken 19134 times.
✓ Branch 11 taken 8097137 times.
293721205 dopos(0, 0, 1, 1);
7558
11/12
✓ Branch 0 taken 7127956 times.
✓ Branch 1 taken 148505820 times.
✓ Branch 2 taken 148495612 times.
✓ Branch 3 taken 10208 times.
✓ Branch 4 taken 10208 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 146853521 times.
✓ Branch 7 taken 1642091 times.
✓ Branch 8 taken 693230 times.
✓ Branch 9 taken 948861 times.
✓ Branch 10 taken 936616 times.
✓ Branch 11 taken 12245 times.
304129388 dopos(0, 0,-1, 1);
7559
11/12
✓ Branch 0 taken 4261059 times.
✓ Branch 1 taken 151372717 times.
✓ Branch 2 taken 150500342 times.
✓ Branch 3 taken 872375 times.
✓ Branch 4 taken 872375 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 117317592 times.
✓ Branch 7 taken 33182750 times.
✓ Branch 8 taken 33121024 times.
✓ Branch 9 taken 61726 times.
✓ Branch 10 taken 23460 times.
✓ Branch 11 taken 38266 times.
306134118 dopos(1, 0, 0, 1);
7560
11/12
✓ Branch 0 taken 6532603 times.
✓ Branch 1 taken 149101173 times.
✓ Branch 2 taken 149090458 times.
✓ Branch 3 taken 10715 times.
✓ Branch 4 taken 10715 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 112144240 times.
✓ Branch 7 taken 36946218 times.
✓ Branch 8 taken 30144698 times.
✓ Branch 9 taken 6801520 times.
✓ Branch 10 taken 6371230 times.
✓ Branch 11 taken 430290 times.
304724234 dopos(-1, 0, 0, 1);
7561
11/12
✓ Branch 0 taken 5414114 times.
✓ Branch 1 taken 150219662 times.
✓ Branch 2 taken 129089038 times.
✓ Branch 3 taken 21130624 times.
✓ Branch 4 taken 21130624 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 109060514 times.
✓ Branch 7 taken 20028524 times.
✓ Branch 8 taken 3403076 times.
✓ Branch 9 taken 16625448 times.
✓ Branch 10 taken 14512333 times.
✓ Branch 11 taken 2113115 times.
284722814 dopos(0, 1, 0, 1);
7562
11/12
✓ Branch 0 taken 4163636 times.
✓ Branch 1 taken 151470140 times.
✓ Branch 2 taken 151261759 times.
✓ Branch 3 taken 208381 times.
✓ Branch 4 taken 208381 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 139348817 times.
✓ Branch 7 taken 11912942 times.
✓ Branch 8 taken 11795114 times.
✓ Branch 9 taken 117828 times.
✓ Branch 10 taken 87731 times.
✓ Branch 11 taken 30097 times.
306895535 dopos(0,-1, 0, 1);
7563 #ifdef _MSC_VER
7564 #pragma warning(default:4127)
7565 #endif
7566
7567 /* faster growing of blue direction */
7568
4/4
✓ Branch 0 taken 148505820 times.
✓ Branch 1 taken 7127956 times.
✓ Branch 2 taken 693230 times.
✓ Branch 3 taken 147812590 times.
155633776 if((b > 0) && (data[first-1] == val))
7569 {
7570 147812590 b -= 2;
7571 147812590 first--;
7572 147812590 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7573
7574 #ifdef _MSC_VER
7575 #pragma warning(disable:4127)
7576 #endif
7577
5/6
✓ Branch 0 taken 6133983 times.
✓ Branch 1 taken 141678607 times.
✓ Branch 2 taken 141677331 times.
✓ Branch 3 taken 1276 times.
✓ Branch 4 taken 1276 times.
✗ Branch 5 not taken.
289489921 dopos(-1, 0, 0, 0);
7578
5/6
✓ Branch 0 taken 4132521 times.
✓ Branch 1 taken 143680069 times.
✓ Branch 2 taken 143607601 times.
✓ Branch 3 taken 72468 times.
✓ Branch 4 taken 72468 times.
✗ Branch 5 not taken.
291420191 dopos(1, 0, 0, 0);
7579
5/6
✓ Branch 0 taken 4002458 times.
✓ Branch 1 taken 143810132 times.
✓ Branch 2 taken 143770582 times.
✓ Branch 3 taken 39550 times.
✓ Branch 4 taken 39550 times.
✗ Branch 5 not taken.
291583172 dopos(0,-1, 0, 0);
7580
5/6
✓ Branch 0 taken 5136865 times.
✓ Branch 1 taken 142675725 times.
✓ Branch 2 taken 142202518 times.
✓ Branch 3 taken 473207 times.
✓ Branch 4 taken 473207 times.
✗ Branch 5 not taken.
290015108 dopos(0, 1, 0, 0);
7581 #ifdef _MSC_VER
7582 #pragma warning(default:4127)
7583 #endif
7584
7585 147812590 first++;
7586 147812590 }
7587
7588 /* get next from list */
7589 155633776 i = first;
7590 155633776 first = next[first];
7591 155633776 next[i] = UNUSED;
7592
7593 /* second version of loop */
7594
2/2
✓ Branch 0 taken 6376 times.
✓ Branch 1 taken 155627400 times.
155633776 if(first != LAST)
7595 {
7596 155627400 depos(first, r, g, b);
7597
7598 155627400 val = data[first];
7599 155627400 r2 = (col_diff+128)[((pal[val].r)-(r)) & 0x7F];
7600 155627400 g2 = (col_diff)[((pal[val].g)-(g)) & 0x7F];
7601 155627400 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7602
7603 #ifdef _MSC_VER
7604 #pragma warning(disable:4127)
7605 #endif
7606
11/12
✓ Branch 0 taken 4185066 times.
✓ Branch 1 taken 151442334 times.
✓ Branch 2 taken 135285246 times.
✓ Branch 3 taken 16157088 times.
✓ Branch 4 taken 16157088 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 125927933 times.
✓ Branch 7 taken 9357313 times.
✓ Branch 8 taken 3017627 times.
✓ Branch 9 taken 6339686 times.
✓ Branch 10 taken 17090 times.
✓ Branch 11 taken 6322596 times.
290912646 dopos(0, 0, 1, 1);
7607
11/12
✓ Branch 0 taken 7198074 times.
✓ Branch 1 taken 148429326 times.
✓ Branch 2 taken 148427541 times.
✓ Branch 3 taken 1785 times.
✓ Branch 4 taken 1785 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 146826279 times.
✓ Branch 7 taken 1601262 times.
✓ Branch 8 taken 663643 times.
✓ Branch 9 taken 937619 times.
✓ Branch 10 taken 921799 times.
✓ Branch 11 taken 15820 times.
304054941 dopos(0, 0,-1, 1);
7608
11/12
✓ Branch 0 taken 4095805 times.
✓ Branch 1 taken 151531595 times.
✓ Branch 2 taken 150384589 times.
✓ Branch 3 taken 1147006 times.
✓ Branch 4 taken 1147006 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 116863620 times.
✓ Branch 7 taken 33520969 times.
✓ Branch 8 taken 33468684 times.
✓ Branch 9 taken 52285 times.
✓ Branch 10 taken 21420 times.
✓ Branch 11 taken 30865 times.
306011989 dopos(1, 0, 0, 1);
7609
11/12
✓ Branch 0 taken 6264382 times.
✓ Branch 1 taken 149363018 times.
✓ Branch 2 taken 149355621 times.
✓ Branch 3 taken 7397 times.
✓ Branch 4 taken 7397 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 112258298 times.
✓ Branch 7 taken 37097323 times.
✓ Branch 8 taken 30294330 times.
✓ Branch 9 taken 6802993 times.
✓ Branch 10 taken 6440038 times.
✓ Branch 11 taken 362955 times.
304983021 dopos(-1, 0, 0, 1);
7610
11/12
✓ Branch 0 taken 5534712 times.
✓ Branch 1 taken 150092688 times.
✓ Branch 2 taken 104334770 times.
✓ Branch 3 taken 45757918 times.
✓ Branch 4 taken 45757918 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 85026191 times.
✓ Branch 7 taken 19308579 times.
✓ Branch 8 taken 3457658 times.
✓ Branch 9 taken 15850921 times.
✓ Branch 10 taken 14382281 times.
✓ Branch 11 taken 1468640 times.
259962170 dopos(0, 1, 0, 1);
7611
11/12
✓ Branch 0 taken 4266668 times.
✓ Branch 1 taken 151360732 times.
✓ Branch 2 taken 151112571 times.
✓ Branch 3 taken 248161 times.
✓ Branch 4 taken 248161 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 139288661 times.
✓ Branch 7 taken 11823910 times.
✓ Branch 8 taken 11689495 times.
✓ Branch 9 taken 134415 times.
✓ Branch 10 taken 108396 times.
✓ Branch 11 taken 26019 times.
306739971 dopos(0,-1, 0, 1);
7612 #ifdef _MSC_VER
7613 #pragma warning(default:4127)
7614 #endif
7615
7616
4/4
✓ Branch 0 taken 151442334 times.
✓ Branch 1 taken 4185066 times.
✓ Branch 2 taken 3017627 times.
✓ Branch 3 taken 148424707 times.
155627400 if((b < 61) && (data[first + 1] == val))
7617 {
7618 148424707 b += 2;
7619 148424707 first++;
7620 148424707 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7f];
7621
7622 #ifdef _MSC_VER
7623 #pragma warning(disable:4127)
7624 #endif
7625
5/6
✓ Branch 0 taken 5940237 times.
✓ Branch 1 taken 142484470 times.
✓ Branch 2 taken 134036317 times.
✓ Branch 3 taken 8448153 times.
✓ Branch 4 taken 8448153 times.
✗ Branch 5 not taken.
282461024 dopos(-1, 0, 0, 0);
7626
5/6
✓ Branch 0 taken 3975939 times.
✓ Branch 1 taken 144448768 times.
✓ Branch 2 taken 99515130 times.
✓ Branch 3 taken 44933638 times.
✓ Branch 4 taken 44933638 times.
✗ Branch 5 not taken.
247939837 dopos(1, 0, 0, 0);
7627
5/6
✓ Branch 0 taken 4129719 times.
✓ Branch 1 taken 144294988 times.
✓ Branch 2 taken 140668468 times.
✓ Branch 3 taken 3626520 times.
✓ Branch 4 taken 3626520 times.
✗ Branch 5 not taken.
289093175 dopos(0,-1, 0, 0);
7628
5/6
✓ Branch 0 taken 5253635 times.
✓ Branch 1 taken 143171072 times.
✓ Branch 2 taken 32418332 times.
✓ Branch 3 taken 110752740 times.
✓ Branch 4 taken 110752740 times.
✗ Branch 5 not taken.
180843039 dopos(0, 1, 0, 0);
7629 #ifdef _MSC_VER
7630 #pragma warning(default:4127)
7631 #endif
7632
7633 148424707 first--;
7634 148424707 }
7635
7636 155627400 i = first;
7637 155627400 first = next[first];
7638 155627400 next[i] = UNUSED;
7639 155627400 }
7640
7641 155633776 count++;
7642
7643
2/2
✓ Branch 0 taken 153537419 times.
✓ Branch 1 taken 2096357 times.
155633776 if(count == (cbcount+1)*AVERAGE_COUNT/256)
7644 {
7645
2/2
✓ Branch 0 taken 7141 times.
✓ Branch 1 taken 2089216 times.
2096357 if(cbcount < 256)
7646 {
7647
1/2
✓ Branch 0 taken 2089216 times.
✗ Branch 1 not taken.
2089216 if(callback)
7648 callback(cbcount);
7649
7650 2089216 cbcount++;
7651 2089216 }
7652 2096357 }
7653 }
7654
7655
1/2
✓ Branch 0 taken 8161 times.
✗ Branch 1 not taken.
8161 if(callback)
7656 while(cbcount < 256)
7657 callback(cbcount++);
7658 8161 }
7659
7660 int32_t short_bmp_avg(BITMAP *bmp, int32_t i)
7661 {
7662 int32_t j=((int16_t *)bmp->line[0])[i];
7663 int32_t r=getr15(j);
7664 int32_t g=getg15(j);
7665 int32_t b=getb15(j);
7666 int32_t k=1;
7667
7668 if(i>0)
7669 {
7670 j=((int16_t *)bmp->line[0])[i-1];
7671 r+=getr15(j);
7672 g+=getg15(j);
7673 b+=getb15(j);
7674 ++k;
7675 }
7676
7677 if(i<(bmp->w-2))
7678 {
7679 j=((int16_t *)bmp->line[0])[i+1];
7680 r+=getr15(j);
7681 g+=getg15(j);
7682 b+=getb15(j);
7683 ++k;
7684 }
7685
7686 r/=k;
7687 g/=k;
7688 b/=k;
7689 return makecol15(r, g, b);
7690 }
7691
7692 // A consistent RENG (random enough number generator) for dither_rect()
7693 static uint16_t lfsr;
7694
7695 void lfsrInit()
7696 {
7697 lfsr=1;
7698 }
7699
7700 uint16_t lfsrNext()
7701 {
7702 auto bits=(lfsr^(lfsr>>2)^(lfsr>>3)^(lfsr>>5))&1;
7703 lfsr=(lfsr>>1)|(bits<<15);
7704 return lfsr;
7705 }
7706
7707 void dither_rect(BITMAP *bmp, PALETTE *pal, int32_t x1, int32_t y1, int32_t x2, int32_t y2,
7708 int32_t src_color1, int32_t src_color2, uint8_t dest_color1,
7709 uint8_t dest_color2)
7710 {
7711 BITMAP *src_bmp=create_bitmap_ex(15, abs(x2-x1)+1, 1);
7712 BITMAP *dest_bmp=create_bitmap_ex(8, abs(x2-x1)+1, abs(y2-y1)+1);
7713 int32_t r, g, b, direction=1;
7714 int32_t c;
7715 int32_t r1, r2, g1, g2, b1, b2;
7716 int32_t (*diff[2])[3];
7717 diff[0] = new int32_t[x2-x1+3][3];
7718 diff[1] = new int32_t[x2-x1+3][3];
7719 int32_t cdiff[3];
7720 RGB_MAP table;
7721 int32_t temp;
7722 int32_t red_rand_strength=0, green_rand_strength=0, blue_rand_strength=0;
7723
7724 lfsrInit();
7725 clear_bitmap(dest_bmp);
7726
7727 if(x1>x2)
7728 {
7729 temp=x1;
7730 x1=x2;
7731 x2=temp;
7732 }
7733
7734 if(y1>y2)
7735 {
7736 temp=y1;
7737 y1=y2;
7738 y2=temp;
7739 }
7740
7741 if(src_color1>src_color2)
7742 {
7743 temp=src_color1;
7744 src_color1=src_color2;
7745 src_color2=temp;
7746 }
7747
7748 if(dest_color1>dest_color2)
7749 {
7750 temp=dest_color1;
7751 dest_color1=dest_color2;
7752 dest_color2=temp;
7753 }
7754
7755 create_rgb_table_range(&table, *pal, dest_color1, dest_color2, NULL);
7756 r1=getr15(src_color1);
7757 r2=getr15(src_color2);
7758 g1=getg15(src_color1);
7759 g2=getg15(src_color2);
7760 b1=getb15(src_color1);
7761 b2=getb15(src_color2);
7762 red_rand_strength=getr8(dest_color1+1)-getr8(dest_color1);
7763 green_rand_strength=getg8(dest_color1+1)-getg8(dest_color1);
7764 blue_rand_strength=getb8(dest_color1+1)-getb8(dest_color1);
7765 memset(cdiff,0,3*sizeof(float));
7766 memset(diff[0],0,(x2-x1+3)*3*sizeof(int32_t));
7767 memset(diff[1],0,(x2-x1+3)*3*sizeof(int32_t));
7768 int32_t mc, mr, mg, mb;
7769
7770 for(int32_t i=0; i<src_bmp->w; i++)
7771 {
7772 r = mix_value(r1, r2, i, src_bmp->w-1);
7773 g = mix_value(g1, g2, i, src_bmp->w-1);
7774 b = mix_value(b1, b2, i, src_bmp->w-1);
7775 c = makecol15(r,g,b);
7776 ((int16_t *)src_bmp->line[0])[i] = c;
7777 }
7778
7779 uint8_t tempcolor, origcolor;
7780
7781 for(int32_t j=0; j<=y2-y1; ++j)
7782 {
7783 if(direction==1)
7784 {
7785 for(int32_t i=0; i<=x2-x1; ++i)
7786 {
7787 mc=((int16_t *)src_bmp->line[0])[i];
7788 mr=bound(getr15(mc)+lfsrNext()%(red_rand_strength*2+1)-(red_rand_strength*1),0,255);
7789 mg=bound(getg15(mc)+lfsrNext()%(green_rand_strength*2+1)-(green_rand_strength*1),0,255);
7790 mb=bound(getb15(mc)+lfsrNext()%(blue_rand_strength*2+1)-(blue_rand_strength*1),0,255);
7791 cdiff[0]=bound(mr+
7792 diff[0][i][0]+
7793 diff[0][i+1][0]+
7794 diff[0][i+2][0]+
7795 cdiff[0],0,255);
7796 cdiff[1]=bound(mg+
7797 diff[0][i][1]+
7798 diff[0][i+1][1]+
7799 diff[0][i+2][1]+
7800 cdiff[1],0,255);
7801 cdiff[2]=bound(mb+
7802 diff[0][i][2]+
7803 diff[0][i+1][2]+
7804 diff[0][i+2][2]+
7805 cdiff[2],0,255);
7806 // bmp->line[j][i+x1]=bound(makecol8_map(int32_t(cdiff[0]),int32_t(cdiff[1]),int32_t(cdiff[2]),&table),dest_color1,dest_color2);
7807 origcolor=makecol8_map(mr,mg,mb,&table);
7808 // tempcolor=bound(makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table),origcolor-1,origcolor+1);
7809 tempcolor=makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table);
7810 dest_bmp->line[j][i]=tempcolor;
7811 r=getr8(tempcolor);
7812 g=getg8(tempcolor);
7813 b=getb8(tempcolor);
7814 diff[1][i][0]=(cdiff[0]-r)*3/16;
7815 diff[1][i][1]=(cdiff[1]-g)*3/16;
7816 diff[1][i][2]=(cdiff[2]-b)*3/16;
7817 diff[1][i+1][0]=(cdiff[0]-r)*5/16;
7818 diff[1][i+1][1]=(cdiff[1]-g)*5/16;
7819 diff[1][i+1][2]=(cdiff[2]-b)*5/16;
7820 diff[1][i+2][0]=(cdiff[0]-r)*1/16;
7821 diff[1][i+2][1]=(cdiff[1]-g)*1/16;
7822 diff[1][i+2][2]=(cdiff[2]-b)*1/16;
7823 cdiff[0]=(cdiff[0]-r)*7/16;
7824 cdiff[1]=(cdiff[1]-g)*7/16;
7825 cdiff[2]=(cdiff[2]-b)*7/16;
7826 }
7827
7828 memcpy(diff[0],diff[1],(x2-x1+3)*3*sizeof(int32_t));
7829 memset(diff[1],0,(x2-x1+3)*3*sizeof(int32_t));
7830 direction=-1;
7831 }
7832 else
7833 {
7834 for(int32_t i=x2-x1; i>=0; --i)
7835 {
7836 mc=((int16_t *)src_bmp->line[0])[i];
7837 mr=getr15(mc);
7838 mg=getg15(mc);
7839 mb=getb15(mc);
7840 cdiff[0]=bound(mr+
7841 diff[0][i][0]+
7842 diff[0][i+1][0]+
7843 diff[0][i+2][0]+
7844 cdiff[0],0,255);
7845 cdiff[1]=bound(mg+
7846 diff[0][i][1]+
7847 diff[0][i+1][1]+
7848 diff[0][i+2][1]+
7849 cdiff[1],0,255);
7850 cdiff[2]=bound(mb+
7851 diff[0][i][2]+
7852 diff[0][i+1][2]+
7853 diff[0][i+2][2]+
7854 cdiff[2],0,255);
7855 // bmp->line[j][i+x1]=bound(makecol8_map(int32_t(cdiff[0]),int32_t(cdiff[1]),int32_t(cdiff[2]),&table),dest_color1,dest_color2);
7856 origcolor=makecol8_map(mr,mg,mb,&table);
7857 // tempcolor=bound(makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table),origcolor-1,origcolor+1);
7858 tempcolor=makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table);
7859 dest_bmp->line[j][i]=tempcolor;
7860 r=getr8(tempcolor);
7861 g=getg8(tempcolor);
7862 b=getb8(tempcolor);
7863 diff[1][i][0]=(cdiff[0]-r)*3/16;
7864 diff[1][i][1]=(cdiff[1]-g)*3/16;
7865 diff[1][i][2]=(cdiff[2]-b)*3/16;
7866 diff[1][i+1][0]=(cdiff[0]-r)*5/16;
7867 diff[1][i+1][1]=(cdiff[1]-g)*5/16;
7868 diff[1][i+1][2]=(cdiff[2]-b)*5/16;
7869 diff[1][i+2][0]=(cdiff[0]-r)*1/16;
7870 diff[1][i+2][1]=(cdiff[1]-g)*1/16;
7871 diff[1][i+2][2]=(cdiff[2]-b)*1/16;
7872 cdiff[0]=(cdiff[0]-r)*7/16;
7873 cdiff[1]=(cdiff[1]-g)*7/16;
7874 cdiff[2]=(cdiff[2]-b)*7/16;
7875 }
7876
7877 memcpy(diff[0],diff[1],(x2-x1+3)*3*sizeof(float));
7878 memset(diff[1],0,(x2-x1+3)*3*sizeof(float));
7879 direction=1;
7880 }
7881 }
7882
7883 blit(dest_bmp, bmp, 0, 0, x1, y1, x2-x1+1, y2-y1+1);
7884 delete[] diff[1];
7885 delete[] diff[0];
7886 destroy_bitmap(src_bmp);
7887 destroy_bitmap(dest_bmp);
7888 return;
7889 }
7890
7891 bool do_text_button(int32_t x,int32_t y,int32_t w,int32_t h,const char *text)
7892 {
7893 bool over=false;
7894
7895 while(gui_mouse_b())
7896 {
7897 if(mouse_in_rect(x,y,w,h))
7898 {
7899 if(!over)
7900 {
7901 vsync();
7902 jwin_draw_text_button(screen, x, y, w, h, text, D_SELECTED, true);
7903 over=true;
7904 update_hw_screen();
7905 }
7906 }
7907 else
7908 {
7909 if(over)
7910 {
7911 vsync();
7912 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
7913 over=false;
7914 update_hw_screen();
7915 }
7916 }
7917 rest(1);
7918 }
7919
7920 return over;
7921 }
7922
7923 bool do_text_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,const char *text)
7924 {
7925 bool over=false;
7926
7927 while(gui_mouse_b())
7928 {
7929 //vsync();
7930 if(mouse_in_rect(x,y,w,h))
7931 {
7932 if(!over)
7933 {
7934 vsync();
7935 jwin_draw_text_button(screen, x, y, w, h, text, D_SELECTED, true);
7936 over=true;
7937
7938 update_hw_screen();
7939 }
7940 }
7941 else
7942 {
7943 if(over)
7944 {
7945 vsync();
7946 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
7947 over=false;
7948
7949 update_hw_screen();
7950 }
7951 }
7952 rest(1);
7953 }
7954
7955 if(over)
7956 {
7957 vsync();
7958 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
7959
7960 update_hw_screen();
7961 }
7962
7963 return over;
7964 }
7965 bool do_icon_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,int icon)
7966 {
7967 bool over=false;
7968
7969 while(gui_mouse_b())
7970 {
7971 //vsync();
7972 if(mouse_in_rect(x,y,w,h))
7973 {
7974 if(!over)
7975 {
7976 vsync();
7977 jwin_draw_icon_button(screen, x, y, w, h, icon, D_SELECTED, true);
7978 over=true;
7979
7980 update_hw_screen();
7981 }
7982 }
7983 else
7984 {
7985 if(over)
7986 {
7987 vsync();
7988 jwin_draw_icon_button(screen, x, y, w, h, icon, 0, true);
7989 over=false;
7990
7991 update_hw_screen();
7992 }
7993 }
7994 rest(1);
7995 }
7996
7997 if(over)
7998 {
7999 vsync();
8000 jwin_draw_icon_button(screen, x, y, w, h, icon, 0, true);
8001
8002 update_hw_screen();
8003 }
8004
8005 return over;
8006 }
8007
8008 int32_t jwin_tab_proc(int32_t msg, DIALOG *d, int32_t c)
8009 {
8010 int32_t i;
8011 int32_t tx;
8012 int32_t sd=2; //selected delta
8013 TABPANEL *panel=(TABPANEL *)d->dp;
8014 DIALOG *panel_dialog=NULL, *current_object=NULL;
8015 int32_t selected=0;
8016 int32_t counter=0;
8017 ASSERT(d);
8018 int32_t temp_d, temp_d2;
8019
8020 if(d->dp==NULL) return D_O_K;
8021
8022 panel_dialog=(DIALOG *)d->dp3;
8023
8024 if (msg != MSG_START && msg != MSG_END)
8025 {
8026 bool redraw = false;
8027 for (i = 0; panel[i].text; ++i)
8028 {
8029 if ((panel[i].flags & D_SELECTED) && !(d->flags & D_HIDDEN))
8030 {
8031 for (counter = 0; counter < panel[i].objects; counter++)
8032 {
8033 current_object = panel_dialog + (panel[i].dialog[counter]);
8034 current_object->flags &= ~D_HIDDEN;
8035 if (object_message(current_object, MSG_IDLE, 0) & D_REDRAW)
8036 redraw = true;
8037 }
8038 }
8039 else
8040 {
8041 for (counter = 0; counter < panel[i].objects; counter++)
8042 {
8043 current_object = panel_dialog + (panel[i].dialog[counter]);
8044 current_object->flags |= D_HIDDEN;
8045 if (object_message(current_object, MSG_IDLE, 0) & D_REDRAW)
8046 redraw = true;
8047 }
8048 }
8049
8050 /*if (d->flags & D_HIDDEN)
8051 {
8052 for(counter=0; counter<panel[i].objects; counter++)
8053 {
8054 current_object=panel_dialog+(panel[i].dialog[counter]);
8055 current_object->x=zq_screen_w*3;
8056 current_object->y=zq_screen_h*3;
8057 }
8058 }*/
8059 }
8060 if (redraw)
8061 broadcast_dialog_message(MSG_DRAW, 0);
8062 }
8063 FONT *oldfont = font;
8064 switch(msg)
8065 {
8066 case MSG_DRAW:
8067 {
8068 if(d->x<zq_screen_w&&d->y<zq_screen_h)
8069 {
8070 if(d->dp2)
8071 {
8072 font = (FONT *)d->dp2;
8073 }
8074
8075 panel_dialog=(DIALOG *)d->dp3;
8076 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+8+text_height(font), scheme[jcBOX]); //tab area
8077 rectfill(screen, d->x+1, d->y+sd+text_height(font)+7, d->x+d->w-2, d->y+sd+d->h-2, scheme[jcBOX]); //panel
8078 vline(screen, d->x, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcLIGHT]);
8079 vline(screen, d->x+1, d->y+sd+7+text_height(font), d->y+sd+d->h-3, scheme[jcMEDLT]);
8080 vline(screen, d->x+d->w-2, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcMEDDARK]);
8081 vline(screen, d->x+d->w-1, d->y+sd+7+text_height(font)-1, d->y+sd+d->h-1, scheme[jcDARK]);
8082 hline(screen, d->x+1, d->y+sd+d->h-2, d->x+d->w-3, scheme[jcMEDDARK]);
8083 hline(screen, d->x, d->y+sd+d->h-1, d->x+d->w-2, scheme[jcDARK]);
8084 tx=d->x;
8085
8086 if(d->dp)
8087 {
8088 if(!(panel[((d->d1&0xFF00)>>8)].flags&D_SELECTED))
8089 {
8090 hline(screen, tx+1, d->y+sd+6+text_height(font)+1, tx+2, scheme[jcMEDLT]); //initial bottom
8091 hline(screen, tx, d->y+sd+6+text_height(font), tx+1, scheme[jcLIGHT]); //initial bottom
8092 }
8093
8094 tx+=2;
8095
8096 for(i=0; panel[i].text; ++i)
8097 {
8098 if(panel[i].flags&D_SELECTED)
8099 {
8100 selected=i;
8101 }
8102 }
8103
8104 for(i=((d->d1&0xFF00)>>8); panel[i].text&&i<=last_visible_tab(panel,((d->d1&0xFF00)>>8),d->w); ++i)
8105 {
8106 sd=(panel[i].flags&D_SELECTED)?0:2;
8107
8108 if((i==((d->d1&0xFF00)>>8)) || (!(panel[i-1].flags&D_SELECTED)))
8109 {
8110 vline(screen, tx-(2-sd), d->y+sd+2, d->y+8+text_height(font), scheme[jcLIGHT]); //left side
8111 vline(screen, tx-(2-sd)+1, d->y+sd+2, d->y+8+text_height(font), scheme[jcMEDLT]); //left side
8112 putpixel(screen, tx+1-(2-sd), d->y+sd+1, scheme[jcLIGHT]); //left angle
8113 }
8114
8115 hline(screen, tx+2-(2-sd), d->y+sd, tx+12+(2-sd)+text_length(font, (char *)panel[i].text), scheme[jcLIGHT]); //top
8116 hline(screen, tx+2-(2-sd), d->y+sd+1, tx+12+(2-sd)+text_length(font, (char *)panel[i].text), scheme[jcMEDLT]); //top
8117
8118 if(!(panel[i].flags&D_SELECTED))
8119 {
8120 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, (char *)panel[i].text)+1, scheme[jcLIGHT]); //bottom
8121 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, (char *)panel[i].text)+1, scheme[jcMEDLT]); //bottom
8122 }
8123
8124 tx+=4;
8125 gui_textout_ln(screen, (uint8_t*)panel[i].text, tx+4, d->y+sd+4, scheme[jcBOXFG], scheme[jcBOX], 0);
8126 tx+=text_length(font, (char *)panel[i].text)+10;
8127
8128 if(!(panel[i+1].text) || (!(panel[i+1].flags&D_SELECTED)))
8129 {
8130 putpixel(screen, tx-1+(2-sd), d->y+sd+1, scheme[jcDARK]); //right angle
8131 vline(screen, tx+(2-sd), d->y+sd+2, d->y+8+text_height(font)-1, scheme[jcDARK]); //right side
8132 vline(screen, tx+(2-sd)-1, d->y+sd+2, d->y+8+text_height(font)-(sd?1:0), scheme[jcMEDDARK]); //right side
8133 }
8134
8135 tx++;
8136 }
8137
8138 if(((d->d1&0xFF00)>>8)!=0||last_visible_tab(panel,((d->d1&0xFF00)>>8),d->w)+1<tab_count(panel))
8139 {
8140 jwin_draw_icon_button(screen,d->x+d->w-14,d->y+2, 14, 14, BTNICON_ARROW_RIGHT, 0, true);
8141 jwin_draw_icon_button(screen,d->x+d->w-28,d->y+2, 14, 14, BTNICON_ARROW_LEFT, 0, true);
8142 }
8143 }
8144
8145 if((tx+(2-sd))<(d->x+d->w))
8146 {
8147 hline(screen, tx+(2-sd)-1, d->y+8+text_height(font), d->x+d->w-1, scheme[jcLIGHT]); //ending bottom
8148 hline(screen, tx+(2-sd)-2, d->y+8+text_height(font)+1, d->x+d->w-2, scheme[jcMEDLT]); //ending bottom
8149 }
8150
8151 font = oldfont;
8152
8153 //what dialog is this tab control in (programmer must set manually)
8154 panel_dialog=(DIALOG *)d->dp3;
8155
8156 //for each object handled by the currently selected tab...
8157 for(counter=0; counter<panel[selected].objects; counter++)
8158 {
8159 //assign current_object to one of the controls handled by the tab
8160 current_object=panel_dialog+(panel[selected].dialog[counter]);
8161 //remember the x and y positions of the control
8162 current_object->x=panel[selected].xy[counter*2];
8163 current_object->y=panel[selected].xy[counter*2+1];
8164 object_message(current_object, MSG_DRAW, 0);
8165 }
8166
8167 //if there was a previously selected tab...
8168 if((d->d1&0x00FF)!=0x00FF)
8169 {
8170 //for each object handled by the tab
8171 for(counter=0; counter<panel[d->d1&0xFF].objects; counter++)
8172 {
8173 //assign current_object to one of the controls handled by the tab
8174 current_object=panel_dialog+(panel[d->d1&0xFF].dialog[counter]);
8175 // //remember the x and y positions of the control
8176 // panel[d->d1].xy[counter*2]=current_object->x;
8177 // panel[d->d1].xy[counter*2+1]=current_object->y;
8178 current_object->x=zq_screen_w*3;
8179 current_object->y=zq_screen_h*3;
8180 }
8181 }
8182 }
8183 }
8184 break;
8185
8186 case MSG_CLICK:
8187 {
8188 d->d1&=0xFF00;
8189 d->d1|=0x00FF;
8190 if(d->dp2)
8191 {
8192 font = (FONT *)d->dp2;
8193 }
8194
8195 // is the mouse on one of the tab arrows (if visible) or in the tab area?
8196 if(uses_tab_arrows(panel, d->w)&&(mouse_in_rect(d->x+d->w-28, d->y+2, 28, 14)))
8197 {
8198 if(mouse_in_rect(d->x+d->w-28, d->y+2, 14, 14))
8199 {
8200 if(do_icon_button_reset(d->x+d->w-28, d->y+2, 14, 14, BTNICON_ARROW_LEFT))
8201 {
8202 temp_d=((d->d1&0xFF00)>>8);
8203 temp_d2=(d->d1&0x00FF);
8204
8205 if(temp_d>0)
8206 {
8207 --temp_d;
8208 }
8209
8210 d->d1=(temp_d<<8)|temp_d2;
8211 d->flags|=D_DIRTY;
8212 }
8213 }
8214 else if(mouse_in_rect(d->x+d->w-14, d->y+2, 14, 14))
8215 {
8216 if(do_icon_button_reset(d->x+d->w-14, d->y+2, 14, 14, BTNICON_ARROW_RIGHT))
8217 {
8218 temp_d=((d->d1&0xFF00)>>8);
8219 temp_d2=(d->d1&0x00FF);
8220
8221 if(last_visible_tab(panel, temp_d, d->w)<(tab_count(panel)-1))
8222 {
8223 ++temp_d;
8224 }
8225
8226 d->d1=(temp_d<<8)|temp_d2;
8227 d->flags|=D_DIRTY;
8228 }
8229 }
8230 }
8231 else
8232 {
8233 d_tab_proc(msg, d, c);
8234 }
8235 font = oldfont;
8236 jwin_tab_proc(MSG_IDLE,d,0);
8237 }
8238 break;
8239
8240 default:
8241 return d_tab_proc(msg, d, c);
8242 break;
8243 }
8244
8245 panel_dialog=(DIALOG *)d->dp3;
8246
8247 if(d->flags & D_HIDDEN)
8248 {
8249 for(i=0; panel[i].text; ++i)
8250 {
8251 for(counter=0; counter<panel[i].objects; counter++)
8252 {
8253 current_object=panel_dialog+(panel[i].dialog[counter]);
8254 current_object->x=zq_screen_w*3;
8255 current_object->y=zq_screen_h*3;
8256 }
8257 }
8258
8259 //d->x=zq_screen_w*3;
8260 //d->y=zq_screen_h*3;
8261 }
8262 else
8263 {
8264 for(i=0; panel[i].text; ++i)
8265 {
8266 for(counter=0; counter<panel[i].objects; counter++)
8267 {
8268 current_object=panel_dialog+(panel[i].dialog[counter]);
8269 current_object->x=panel[i].xy[counter*2];
8270 current_object->y=panel[i].xy[counter*2+1];
8271 }
8272 }
8273
8274 // d->x=zq_screen_w*3;
8275 //d->y=zq_screen_h*3;
8276 }
8277
8278 return broadcast_dialog_message(MSG_IDLE, 0);
8279
8280 // return D_O_K;
8281 }
8282
8283 int32_t discern_tab(GUI::TabPanel *panel, int32_t first_tab, int32_t x)
8284 {
8285 int32_t w=0;
8286
8287 for(size_t i=first_tab; i < panel->getSize(); i++)
8288 {
8289 w+=text_length(font, panel->getName(i))+15;
8290
8291 if(w>x)
8292 {
8293 return i;
8294 }
8295 }
8296
8297 return -1;
8298 }
8299 int32_t tabs_width(GUI::TabPanel *panel)
8300 {
8301 int32_t w=0;
8302
8303 for(size_t i=0; i < panel->getSize(); ++i)
8304 {
8305 w+=text_length(font, panel->getName(i))+15;
8306 }
8307
8308 return w+1;
8309 }
8310 bool uses_tab_arrows(GUI::TabPanel *panel, int32_t maxwidth)
8311 {
8312 return (tabs_width(panel)>maxwidth);
8313 }
8314 size_t last_visible_tab(GUI::TabPanel *panel, int32_t first_tab, int32_t maxwidth)
8315 {
8316 size_t i;
8317 int32_t w=0;
8318
8319 if(uses_tab_arrows(panel, maxwidth))
8320 {
8321 maxwidth-=28;
8322 }
8323
8324 for(i=first_tab; i < panel->getSize(); ++i)
8325 {
8326 w+=text_length(font, panel->getName(i))+15;
8327
8328 if(w>maxwidth)
8329 {
8330 return i-1;
8331 }
8332 }
8333
8334 return i-1;
8335 }
8336 int32_t displayed_tabs_width(GUI::TabPanel *panel, int32_t first_tab, int32_t maxwidth)
8337 {
8338 size_t i=0;
8339 int32_t w=0;
8340
8341 for(i=first_tab; i<=last_visible_tab(panel, first_tab, maxwidth); ++i)
8342 {
8343 w+=text_length(font, panel->getName(i))+15;
8344 }
8345
8346 return w+1;
8347 }
8348
8349 INLINE int32_t is_in_rect(int32_t x,int32_t y,int32_t rx1,int32_t ry1,int32_t rx2,int32_t ry2)
8350 {
8351 return x>=rx1 && x<=rx2 && y>=ry1 && y<=ry2;
8352 }
8353
8354 int32_t new_tab_proc(int32_t msg, DIALOG *d, int32_t c)
8355 {
8356 assert(d->flags&D_NEW_GUI);
8357
8358 int32_t tx;
8359 int32_t ret = D_O_K;
8360 int32_t sd=2; //selected delta
8361 static bool skipredraw = false;
8362 GUI::TabPanel *panel=(GUI::TabPanel*)d->dp;
8363 ASSERT(d);
8364
8365 if(d->dp==NULL) return D_O_K;
8366
8367 FONT *oldfont = font;
8368 if(d->dp2)
8369 {
8370 font = (FONT *)d->dp2;
8371 }
8372
8373 switch(msg)
8374 {
8375 case MSG_DRAW:
8376 {
8377 if(skipredraw)
8378 {
8379 skipredraw = false;
8380 ret = D_REDRAW;
8381 break;
8382 }
8383 if(d->x<zq_screen_w&&d->y<zq_screen_h)
8384 {
8385 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+8+text_height(font), scheme[jcBOX]); //tab area
8386 rectfill(screen, d->x+1, d->y+sd+text_height(font)+7, d->x+d->w-2, d->y+sd+d->h-2, scheme[jcBOX]); //panel
8387 vline(screen, d->x, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcLIGHT]);
8388 vline(screen, d->x+1, d->y+sd+7+text_height(font), d->y+sd+d->h-3, scheme[jcMEDLT]);
8389 vline(screen, d->x+d->w-2, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcMEDDARK]);
8390 vline(screen, d->x+d->w-1, d->y+sd+7+text_height(font)-1, d->y+sd+d->h-1, scheme[jcDARK]);
8391 hline(screen, d->x+1, d->y+sd+d->h-2, d->x+d->w-3, scheme[jcMEDDARK]);
8392 hline(screen, d->x, d->y+sd+d->h-1, d->x+d->w-2, scheme[jcDARK]);
8393 tx=d->x;
8394
8395 if(d->dp)
8396 {
8397 if(panel->getCurrentIndex() != d->d1)
8398 {
8399 hline(screen, tx+1, d->y+sd+6+text_height(font)+1, tx+2, scheme[jcMEDLT]); //initial bottom
8400 hline(screen, tx, d->y+sd+6+text_height(font), tx+1, scheme[jcLIGHT]); //initial bottom
8401 }
8402
8403 tx+=2;
8404
8405 for(size_t i=d->d1; i < panel->getSize()&&i<=last_visible_tab(panel,d->d1,d->w); ++i)
8406 {
8407 sd=(i==panel->getCurrentIndex())?0:2;
8408
8409 if((i==d->d1) || (i-1 != panel->getCurrentIndex()))
8410 {
8411 vline(screen, tx-(2-sd), d->y+sd+2, d->y+8+text_height(font), scheme[jcLIGHT]); //left side
8412 vline(screen, tx-(2-sd)+1, d->y+sd+2, d->y+8+text_height(font), scheme[jcMEDLT]); //left side
8413 putpixel(screen, tx+1-(2-sd), d->y+sd+1, scheme[jcLIGHT]); //left angle
8414 }
8415
8416 hline(screen, tx+2-(2-sd), d->y+sd, tx+12+(2-sd)+text_length(font, panel->getName(i)), scheme[jcLIGHT]); //top
8417 hline(screen, tx+2-(2-sd), d->y+sd+1, tx+12+(2-sd)+text_length(font, panel->getName(i)), scheme[jcMEDLT]); //top
8418
8419 if(i!=panel->getCurrentIndex())
8420 {
8421 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, panel->getName(i))+1, scheme[jcLIGHT]); //bottom
8422 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, panel->getName(i))+1, scheme[jcMEDLT]); //bottom
8423 }
8424 else if(d->flags & D_GOTFOCUS)
8425 {
8426 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, panel->getName(i))+1, scheme[jcBOXFG]); //bottom
8427 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, panel->getName(i))+1, scheme[jcBOXFG]); //bottom
8428 }
8429
8430 tx+=4;
8431 uint8_t* pname = (uint8_t*)(panel->getName(i));
8432 bool dis = panel->getDisabled(i);
8433 if(dis)
8434 gui_textout_ln(screen, pname, tx+5, d->y+sd+5, scheme[jcLIGHT], scheme[jcBOX], 0);
8435 gui_textout_ln(screen, pname, tx+4, d->y+sd+4, scheme[dis ? jcDISABLED_FG : jcBOXFG], dis ? -1 : scheme[jcBOX], 0);
8436 tx+=text_length(font, (const char*)pname)+10;
8437
8438 if((i+1>=panel->getSize()) || (i+1!=panel->getCurrentIndex()))
8439 {
8440 putpixel(screen, tx-1+(2-sd), d->y+sd+1, scheme[jcDARK]); //right angle
8441 vline(screen, tx+(2-sd), d->y+sd+2, d->y+8+text_height(font)-1, scheme[jcDARK]); //right side
8442 vline(screen, tx+(2-sd)-1, d->y+sd+2, d->y+8+text_height(font)-(sd?1:0), scheme[jcMEDDARK]); //right side
8443 }
8444
8445 tx++;
8446 }
8447
8448 if(d->d1!=0||last_visible_tab(panel,d->d1,d->w)+1<panel->getSize())
8449 {
8450 jwin_draw_icon_button(screen,d->x+d->w-14,d->y+2, 14, 14, BTNICON_ARROW_RIGHT, 0, true);
8451 jwin_draw_icon_button(screen,d->x+d->w-28,d->y+2, 14, 14, BTNICON_ARROW_LEFT, 0, true);
8452 }
8453 }
8454
8455 if((tx+(2-sd))<(d->x+d->w))
8456 {
8457 hline(screen, tx+(2-sd)-1, d->y+8+text_height(font), d->x+d->w-1, scheme[jcLIGHT]); //ending bottom
8458 hline(screen, tx+(2-sd)-2, d->y+8+text_height(font)+1, d->x+d->w-2, scheme[jcMEDLT]); //ending bottom
8459 }
8460
8461 }
8462 }
8463 break;
8464
8465 case MSG_WANTFOCUS:
8466 // if(gui_mouse_b())
8467 ret = D_WANTFOCUS|D_REDRAW;
8468 break;
8469 case MSG_GOTFOCUS:
8470 case MSG_LOSTFOCUS:
8471 skipredraw = true;
8472 break;
8473 case MSG_CHAR:
8474 {
8475 int32_t ind = panel->getCurrentIndex();
8476 auto oldind = ind;
8477 switch(c>>8)
8478 {
8479 case KEY_LEFT:
8480 do
8481 {
8482 if(ind > 0)
8483 {
8484 --ind;
8485 }
8486 else
8487 {
8488 ind = panel->getSize()-1;
8489 }
8490 }
8491 while(ind != oldind && panel->getDisabled(ind));
8492 break;
8493 case KEY_RIGHT:
8494 do
8495 {
8496 if(ind+1 < signed(panel->getSize()))
8497 {
8498 ++ind;
8499 }
8500 else
8501 {
8502 ind = 0;
8503 }
8504 }
8505 while(ind != oldind && panel->getDisabled(ind));
8506 break;
8507 default: ind = -1;
8508 }
8509 if(ind > -1 && ind != oldind)
8510 {
8511 panel->switchTo(ind);
8512 GUI_EVENT(d, geCHANGE_SELECTION);
8513 ret |= D_USED_CHAR;
8514 }
8515 }
8516 break;
8517
8518 case MSG_CLICK:
8519 {
8520 // is the mouse on one of the tab arrows (if visible) or in the tab area?
8521 if(uses_tab_arrows(panel, d->w)&&(mouse_in_rect(d->x+d->w-28, d->y+2, 28, 14)))
8522 {
8523 if(mouse_in_rect(d->x+d->w-28, d->y+2, 14, 14))
8524 {
8525 if(do_icon_button_reset(d->x+d->w-28, d->y+2, 14, 14, BTNICON_ARROW_LEFT))
8526 {
8527 if(d->d1>0)
8528 {
8529 --d->d1;
8530 }
8531
8532 ret |= D_REDRAW;
8533 }
8534 }
8535 else if(mouse_in_rect(d->x+d->w-14, d->y+2, 14, 14))
8536 {
8537 if(do_icon_button_reset(d->x+d->w-14, d->y+2, 14, 14, BTNICON_ARROW_RIGHT))
8538 {
8539 size_t t = last_visible_tab(panel, d->d1, d->w);
8540 if(t<(panel->getSize()-1))
8541 {
8542 while(t==last_visible_tab(panel, d->d1, d->w))
8543 ++d->d1;
8544 }
8545
8546 ret |= D_REDRAW;
8547 }
8548 }
8549 }
8550 else if(is_in_rect(gui_mouse_x(),gui_mouse_y(), d->x+2, d->y+2, d->x+displayed_tabs_width(panel,((d->d1&0xFF00)>>8),d->w), d->y+text_height(font)+9))
8551 {
8552 // find out what the new tab (tb) will be (where the mouse is)
8553 int32_t newtab = discern_tab(panel, d->d1, gui_mouse_x()-d->x-2);
8554 if(newtab > -1 && newtab != panel->getCurrentIndex() && !panel->getDisabled(newtab))
8555 {
8556 panel->switchTo(newtab);
8557 GUI_EVENT(d, geCHANGE_SELECTION);
8558 }
8559 }
8560 }
8561 break;
8562 }
8563 font = oldfont;
8564 return ret;
8565 }
8566
8567
8568
8569
8570 int32_t jwin_hline_proc(int32_t msg, DIALOG *d, int32_t)
8571 {
8572 ASSERT(d);
8573
8574 if(msg==MSG_DRAW)
8575 {
8576 if(d->w < 1) return D_O_K;
8577 for(int q = 0; q <= d->d1; ++q)
8578 {
8579 if(d->d2&1)
8580 {
8581 hline(screen, d->x, d->y+q, d->x+d->w-1, d->fg);
8582 }
8583 else
8584 {
8585 hline(screen, d->x, d->y-q, d->x+d->w-1, scheme[jcMEDDARK]);
8586 hline(screen, d->x, d->y+1+q, d->x+d->w-1, scheme[jcLIGHT]);
8587 }
8588 }
8589 }
8590
8591 return D_O_K;
8592 }
8593
8594 int32_t jwin_vline_proc(int32_t msg, DIALOG *d, int32_t)
8595 {
8596 ASSERT(d);
8597
8598 if(msg==MSG_DRAW)
8599 {
8600 if(d->h < 1) return D_O_K;
8601 for(int q = 0; q <= d->d1; ++q)
8602 {
8603 if(d->d2&1)
8604 {
8605 vline(screen, d->x+q, d->y, d->y+d->h-1, d->fg);
8606 }
8607 else
8608 {
8609 vline(screen, d->x+q, d->y, d->y+d->h-1, scheme[jcMEDDARK]);
8610 vline(screen, d->x+1-q, d->y, d->y+d->h-1, scheme[jcLIGHT]);
8611 }
8612 }
8613 }
8614
8615 return D_O_K;
8616 }
8617
8618 int32_t jwin_editbox_proc(int32_t msg, DIALOG *d, int32_t c)
8619 {
8620 return d_editbox_proc(msg, d, c);
8621 }
8622
8623 //centers dialog based on first object, which should be the containing window
8624 3590 void jwin_center_dialog(DIALOG *dialog)
8625 {
8626 int32_t xc, yc;
8627 int32_t c;
8628 ASSERT(dialog);
8629
8630 /* how much to move by? */
8631 3590 xc = (zq_screen_w - dialog[0].w) / 2 - dialog[0].x;
8632 3590 yc = (zq_screen_h - dialog[0].h) / 2 - dialog[0].y;
8633
8634 /* move it */
8635
2/2
✓ Branch 0 taken 77982 times.
✓ Branch 1 taken 3590 times.
81572 for(c=0; dialog[c].proc; c++)
8636 {
8637 77982 dialog[c].x += xc;
8638 77982 dialog[c].y += yc;
8639 77982 }
8640 3590 }
8641 //up-left aligns dialog based on first object, which should be the containing window
8642 void jwin_ulalign_dialog(DIALOG *dialog)
8643 {
8644 int32_t xc, yc;
8645 int32_t c;
8646 ASSERT(dialog);
8647
8648 /* how much to move by? */
8649 xc = dialog[0].x;
8650 yc = dialog[0].y;
8651
8652 /* move it */
8653 for(c=0; dialog[c].proc; c++)
8654 {
8655 dialog[c].x -= xc;
8656 dialog[c].y -= yc;
8657 }
8658 }
8659
8660 //Custom slider proc
8661 int32_t d_jslider_proc(int32_t msg, DIALOG *d, int32_t c)
8662 {
8663 BITMAP *gui_bmp = screen;
8664 BITMAP *slhan = NULL;
8665 int32_t oldpos, newpos;
8666 int32_t sfg; /* slider foreground color */
8667 int32_t vert = TRUE; /* flag: is slider vertical? */
8668 int32_t hh = 7; /* handle height (width for horizontal sliders) */
8669 int32_t hmar; /* handle margin */
8670 int32_t slp; /* slider position */
8671 int32_t mp; /* mouse position */
8672 int32_t irange;
8673 int32_t slx, sly, slh, slw;
8674 int32_t msx, msy;
8675 int32_t retval = D_O_K;
8676 int32_t upkey, downkey;
8677 int32_t pgupkey, pgdnkey;
8678 int32_t homekey, endkey;
8679 int32_t delta;
8680 fixed slratio, slmax, slpos;
8681 typedef int32_t (*SLIDER_TYPE)(void*, int32_t);
8682 SLIDER_TYPE proc = NULL;
8683 //int32_t (*proc)(void *cbpointer, int32_t d2value);
8684 int32_t oldval;
8685 ASSERT(d);
8686
8687 /* check for slider direction */
8688 if(d->h < d->w)
8689 vert = FALSE;
8690
8691 /* set up the metrics for the control */
8692 if(d->dp != NULL)
8693 {
8694 slhan = (BITMAP *)d->dp;
8695
8696 if(vert)
8697 hh = slhan->h;
8698 else
8699 hh = slhan->w;
8700 }
8701
8702 hmar = hh/2;
8703 irange = (vert) ? d->h : d->w;
8704 slmax = itofix(irange-hh);
8705 slratio = slmax / (d->d1);
8706 slpos = slratio * d->d2;
8707 slp = fixtoi(slpos);
8708
8709 switch(msg)
8710 {
8711
8712 case MSG_DRAW:
8713 sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
8714
8715 if(vert)
8716 {
8717 rectfill(gui_bmp, d->x, d->y, d->x+d->w/2-2, d->y+d->h-1, d->bg);
8718 rectfill(gui_bmp, d->x+d->w/2-1, d->y, d->x+d->w/2+1, d->y+d->h-1, sfg);
8719 rectfill(gui_bmp, d->x+d->w/2+2, d->y, d->x+d->w-1, d->y+d->h-1, d->bg);
8720 }
8721 else
8722 {
8723 rectfill(gui_bmp, d->x, d->y, d->x+d->w-1, d->y+d->h/2-2, d->bg);
8724 rectfill(gui_bmp, d->x, d->y+d->h/2-1, d->x+d->w-1, d->y+d->h/2+1, sfg);
8725 rectfill(gui_bmp, d->x, d->y+d->h/2+2, d->x+d->w-1, d->y+d->h-1, d->bg);
8726 }
8727
8728 /* okay, background and slot are drawn, now draw the handle */
8729 if(slhan)
8730 {
8731 if(vert)
8732 {
8733 slx = d->x+(d->w/2)-(slhan->w/2);
8734 sly = d->y+(d->h-1)-(hh+slp);
8735 }
8736 else
8737 {
8738 slx = d->x+slp;
8739 sly = d->y+(d->h/2)-(slhan->h/2);
8740 }
8741
8742 draw_sprite(gui_bmp, slhan, slx, sly);
8743 }
8744 else
8745 {
8746 /* draw default handle */
8747 if(vert)
8748 {
8749 slx = d->x;
8750 sly = d->y+(d->h)-(hh+slp);
8751 slw = d->w-1;
8752 slh = hh-1;
8753 }
8754 else
8755 {
8756 slx = d->x+slp;
8757 sly = d->y;
8758 slw = hh-1;
8759 slh = d->h-1;
8760 }
8761
8762 /* draw body */
8763 rectfill(gui_bmp, slx+2, sly, slx+(slw-2), sly+slh, sfg);
8764 vline(gui_bmp, slx+1, sly+1, sly+slh-1, sfg);
8765 vline(gui_bmp, slx+slw-1, sly+1, sly+slh-1, sfg);
8766 vline(gui_bmp, slx, sly+2, sly+slh-2, sfg);
8767 vline(gui_bmp, slx+slw, sly+2, sly+slh-2, sfg);
8768 vline(gui_bmp, slx+1, sly+2, sly+slh-2, d->bg);
8769 hline(gui_bmp, slx+2, sly+1, slx+slw-2, d->bg);
8770 putpixel(gui_bmp, slx+2, sly+2, d->bg);
8771 }
8772
8773 if(d->flags & D_GOTFOCUS)
8774 dotted_rect(gui_bmp, d->x, d->y, d->x+d->w-1, d->y+d->h-1, sfg, d->bg);
8775
8776 break;
8777
8778 case MSG_WANTFOCUS:
8779 case MSG_LOSTFOCUS:
8780 return D_WANTFOCUS;
8781
8782 case MSG_KEY:
8783 if(!(d->flags & D_GOTFOCUS))
8784 return D_WANTFOCUS;
8785 else
8786 return D_O_K;
8787
8788 case MSG_CHAR:
8789 /* handle movement keys to move slider */
8790 c >>= 8;
8791
8792 if(vert)
8793 {
8794 upkey = KEY_UP;
8795 downkey = KEY_DOWN;
8796 pgupkey = KEY_PGUP;
8797 pgdnkey = KEY_PGDN;
8798 homekey = KEY_END;
8799 endkey = KEY_HOME;
8800 }
8801 else
8802 {
8803 upkey = KEY_RIGHT;
8804 downkey = KEY_LEFT;
8805 pgupkey = KEY_PGDN;
8806 pgdnkey = KEY_PGUP;
8807 homekey = KEY_HOME;
8808 endkey = KEY_END;
8809 }
8810
8811 if(c == upkey)
8812 delta = 1;
8813 else if(c == downkey)
8814 delta = -1;
8815 else if(c == pgdnkey)
8816 delta = -d->d1 / 16;
8817 else if(c == pgupkey)
8818 delta = d->d1 / 16;
8819 else if(c == homekey)
8820 delta = -d->d2;
8821 else if(c == endkey)
8822 delta = d->d1 - d->d2;
8823 else
8824 delta = 0;
8825
8826 if(delta)
8827 {
8828 oldpos = slp;
8829 oldval = d->d2;
8830
8831 //while (true) {
8832 for(; ;) //thank you, MSVC ~pkmnfrk
8833 {
8834 d->d2 = d->d2+delta;
8835 slpos = slratio*d->d2;
8836 slp = fixtoi(slpos);
8837
8838 if((slp != oldpos) || (d->d2 <= 0) || (d->d2 >= d->d1))
8839 break;
8840 }
8841
8842 if(d->d2 < 0)
8843 d->d2 = 0;
8844
8845 if(d->d2 > d->d1)
8846 d->d2 = d->d1;
8847
8848 retval = D_USED_CHAR;
8849
8850 if(d->d2 != oldval)
8851 {
8852 /* call callback function here */
8853 if(d->dp2)
8854 {
8855 proc = (SLIDER_TYPE)(d->dp2);
8856 retval |= (*proc)(d->dp3, d->d2);
8857 }
8858
8859 GUI_EVENT(d, geCHANGE_VALUE);
8860
8861 object_message(d, MSG_DRAW, 0);
8862 }
8863 }
8864
8865 break;
8866
8867 case MSG_WANTWHEEL:
8868 return 1;
8869
8870 case MSG_WHEEL:
8871 oldval = d->d2;
8872 d->d2 = MID(0, d->d2+c, d->d1);
8873
8874 if(d->d2 != oldval)
8875 {
8876 /* call callback function here */
8877 if(d->dp2)
8878 {
8879 proc = (SLIDER_TYPE)(d->dp2);
8880 retval |= (*proc)(d->dp3, d->d2);
8881 }
8882
8883 GUI_EVENT(d, geCHANGE_VALUE);
8884 object_message(d, MSG_DRAW, 0);
8885 retval |= D_REDRAWME;
8886 }
8887
8888 break;
8889
8890 case MSG_CLICK:
8891 /* track the mouse until it is released */
8892 mp = slp;
8893
8894 while(gui_mouse_b())
8895 {
8896 msx = gui_mouse_x();
8897 msy = gui_mouse_y();
8898 oldval = d->d2;
8899
8900 if(vert)
8901 mp = (d->y+d->h-hmar)-msy;
8902 else
8903 mp = msx-(d->x+hmar);
8904
8905 if(mp < 0)
8906 mp = 0;
8907
8908 if(mp > irange-hh)
8909 mp = irange-hh;
8910
8911 slpos = itofix(mp);
8912 slmax = fixdiv(slpos, slratio);
8913 newpos = fixtoi(slmax);
8914
8915 if(newpos != oldval)
8916 {
8917 d->d2 = newpos;
8918
8919 /* call callback function here */
8920 if(d->dp2 != NULL)
8921 {
8922 proc = (SLIDER_TYPE)(d->dp2);
8923 retval |= (*proc)(d->dp3, d->d2);
8924 }
8925
8926 GUI_EVENT(d, geCHANGE_VALUE);
8927 object_message(d, MSG_DRAW, 0);
8928 }
8929
8930 /* let other objects continue to animate */
8931 broadcast_dialog_message(MSG_IDLE, 0);
8932 update_hw_screen();
8933 }
8934
8935 break;
8936 }
8937
8938 return retval;
8939 }
8940
8941 // This is only used by jwin_check_proc and jwin_radio_proc.
8942 int32_t d_jwinbutton_proc(int32_t msg, DIALOG *d, int32_t)
8943 {
8944 BITMAP *gui_bmp;
8945 int32_t state1, state2;
8946 int32_t black;
8947 int32_t swap;
8948 int32_t g;
8949 ASSERT(d);
8950
8951 gui_bmp = screen;
8952
8953 switch(msg)
8954 {
8955 case MSG_DRAW:
8956 {
8957 if(d->flags & D_SELECTED)
8958 {
8959 g = 1;
8960 state1 = d->bg;
8961 state2 = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
8962 }
8963 else
8964 {
8965 g = 0;
8966 state1 = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
8967 state2 = d->bg;
8968 }
8969
8970 rectfill(gui_bmp, d->x+1+g, d->y+1+g, d->x+d->w-3+g, d->y+d->h-3+g, state2);
8971 rect(gui_bmp, d->x+g, d->y+g, d->x+d->w-2+g, d->y+d->h-2+g, state1);
8972 gui_textout_ex(gui_bmp, (char *)d->dp, d->x+d->w/2+g, d->y+d->h/2-text_height(font)/2+g, state1, -1, TRUE);
8973
8974 if(d->flags & D_SELECTED)
8975 {
8976 vline(gui_bmp, d->x, d->y, d->y+d->h-2, d->bg);
8977 hline(gui_bmp, d->x, d->y, d->x+d->w-2, d->bg);
8978 }
8979 else
8980 {
8981 black = makecol(0,0,0);
8982 vline(gui_bmp, d->x+d->w-1, d->y+1, d->y+d->h-2, black);
8983 hline(gui_bmp, d->x+1, d->y+d->h-1, d->x+d->w-1, black);
8984 }
8985
8986 if((d->flags & D_GOTFOCUS) &&
8987 (!(d->flags & D_SELECTED) || !(d->flags & D_EXIT)))
8988 dotted_rect(gui_bmp, d->x+1+g, d->y+1+g, d->x+d->w-3+g, d->y+d->h-3+g, state1, state2);
8989
8990 break;
8991 }
8992 case MSG_WANTFOCUS:
8993 return D_WANTFOCUS;
8994
8995 case MSG_KEY:
8996 {
8997 /* close dialog? */
8998 if(d->flags & D_EXIT)
8999 {
9000 return D_CLOSE;
9001 }
9002
9003 /* or just toggle */
9004 d->flags ^= D_SELECTED;
9005 GUI_EVENT(d, geTOGGLE);
9006 object_message(d, MSG_DRAW, 0);
9007 break;
9008 }
9009
9010 case MSG_CLICK:
9011 {
9012 /* what state was the button originally in? */
9013 state1 = d->flags & D_SELECTED;
9014
9015 swap = state1;
9016
9017 /* track the mouse until it is released */
9018 while(gui_mouse_b())
9019 {
9020 state2 = ((gui_mouse_x() >= d->x) && (gui_mouse_y() >= d->y) &&
9021 (gui_mouse_x() < d->x + d->w) && (gui_mouse_y() < d->y + d->h));
9022
9023 if(swap)
9024 state2 = !state2;
9025
9026 /* redraw? */
9027 bool should_redraw = false;
9028 if(((state1) && (!state2)) || ((state2) && (!state1)))
9029 {
9030 d->flags ^= D_SELECTED;
9031 GUI_EVENT(d, geTOGGLE);
9032 state1 = d->flags & D_SELECTED;
9033 object_message(d, MSG_DRAW, 0);
9034 should_redraw = true;
9035 }
9036
9037 /* let other objects continue to animate */
9038 int r = broadcast_dialog_message(MSG_IDLE, 0);
9039 if (r & D_REDRAWME) should_redraw = true;
9040
9041 if (should_redraw)
9042 {
9043 update_hw_screen();
9044 }
9045 }
9046
9047 if(d->dp3 != NULL)
9048 {
9049 //object_message(d, MSG_DRAW, 0);
9050 typedef int32_t (*funcType)(void);
9051 funcType func=reinterpret_cast<funcType>(d->dp3);
9052
9053 return func();
9054 }
9055
9056 /* should we close the dialog? */
9057 if(d->flags & D_EXIT)
9058 {
9059 return D_CLOSE;
9060 }
9061 break;
9062 }
9063 }
9064
9065 return D_O_K;
9066 }
9067
9068 //Misc bitmap drawing
9069 void draw_x(BITMAP* dest, int x1, int y1, int x2, int y2, int color)
9070 {
9071 line(dest, x1, y1, x2, y2, color);
9072 line(dest, x1, y2, x2, y1, color);
9073 }
9074
9075 void draw_check(BITMAP* dest, int x1, int y1, int x2, int y2, int c)
9076 {
9077 if(x2 < x1)
9078 zc_swap(x2,x1);
9079 if(y2 < y1)
9080 zc_swap(y2,y1);
9081 int x3 = ((x2-x1)/2)+x1;
9082 int y3 = y2-(x3-x1);
9083 line(dest, x1, y3, x3, y2, c);
9084 line(dest, x3, y2, x2, y1, c);
9085 }
9086
9087 void draw_checkerboard(BITMAP* dest, int x, int y, int sz, optional<int> cb_sz, int offx, int offy)
9088 {
9089 if(!cb_sz)
9090 cb_sz = sz/2;
9091 int ox = -x+offx, oy = -y+offy;
9092 ditherrectfill(dest, x, y, x+sz-1, y+sz-1, vc(CheckerCol1), dithChecker, *cb_sz, ox, oy, vc(CheckerCol2));
9093 }
9094
9095 int32_t d_vsync_proc(int32_t msg,DIALOG *d,int32_t c)
9096 {
9097 // This use to be what kept 60fps, but now render_timer_wait handles that.
9098 switch(msg)
9099 {
9100 case MSG_IDLE:
9101 {
9102 broadcast_dialog_message(MSG_VSYNC, c);
9103 break;
9104 }
9105 }
9106
9107 return D_O_K;
9108 }
9109
9110 //
9111
9112 void draw_checkbox(BITMAP *dest,int x,int y,int sz,bool value)
9113 {
9114 draw_checkbox(dest,x,y,sz,sz,value);
9115 }
9116 void draw_checkbox(BITMAP *dest,int x,int y,int wid,int hei,bool value)
9117 {
9118 jwin_draw_frame(dest, x, y, wid, hei, FR_DEEP);
9119 rectfill(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTBG]);
9120
9121 if(value)
9122 {
9123 line(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTFG]);
9124 line(dest, x+2, y+hei-3, x+wid-3, y+2, jwin_pal[jcTEXTFG]);
9125 }
9126 }
9127 void draw_dis_checkbox(BITMAP *dest,int x,int y,int wid,int hei,bool value)
9128 {
9129 jwin_draw_frame(dest, x, y, wid, hei, FR_DEEP);
9130
9131 if(value)
9132 {
9133 line(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTFG]);
9134 line(dest, x+2, y+hei-3, x+wid-3, y+2, jwin_pal[jcTEXTFG]);
9135 }
9136 }
9137
9138 bool do_scheckbox(BITMAP *dest,int x,int y,int sz,int &value, int xoffs, int yoffs)
9139 {
9140 return do_checkbox(dest,x,y,sz,sz,value,xoffs,yoffs);
9141 }
9142 bool do_checkbox(BITMAP *dest,int x,int y,int wid,int hei,int &value, int xoffs, int yoffs)
9143 {
9144 bool over=false;
9145
9146 while(gui_mouse_b())
9147 {
9148 if(isinRect(gui_mouse_x()-xoffs,gui_mouse_y()-yoffs,x,y,x+wid-1,y+hei-1))
9149 {
9150 if(!over)
9151 {
9152 value=value?0:1;
9153 draw_checkbox(dest,x,y,wid,hei,value!=0);
9154 over=true;
9155 update_hw_screen();
9156 }
9157 }
9158 else
9159 {
9160 if(over)
9161 {
9162 value=value?0:1;
9163 draw_checkbox(dest,x,y,wid,hei,value!=0);
9164 over=false;
9165 update_hw_screen();
9166 }
9167 }
9168 rest(1);
9169 }
9170
9171 return over;
9172 }
9173 bool do_checkbox_tx(BITMAP *dest,int x,int y,int wid,int hei,int &value, int txtoffs, int xoffs, int yoffs)
9174 {
9175 bool over=false;
9176
9177 while(gui_mouse_b())
9178 {
9179 if(isinRect(gui_mouse_x()-xoffs,gui_mouse_y()-yoffs,x,y,x+wid-1+txtoffs,y+hei-1))
9180 {
9181 if(!over)
9182 {
9183 value=value?0:1;
9184 draw_checkbox(dest,x,y,wid,hei,value!=0);
9185 over=true;
9186 update_hw_screen();
9187 }
9188 }
9189 else
9190 {
9191 if(over)
9192 {
9193 value=value?0:1;
9194 draw_checkbox(dest,x,y,wid,hei,value!=0);
9195 over=false;
9196 update_hw_screen();
9197 }
9198 }
9199 rest(1);
9200 }
9201
9202 return over;
9203 }
9204
9205 //box_out stuff
9206 static int32_t box_x = 0;
9207 static int32_t box_y = 0;
9208 static bool box_active=false;
9209 static int32_t box_store_x = 0;
9210 365 static FONT *box_title_font=font;
9211 365 static FONT *box_message_font=font;
9212 static int32_t box_style=0;
9213 static int32_t box_titlebar_height=0;
9214 static int32_t box_message_height=0;
9215 static uint8_t box_text_scale=1;
9216 static int32_t box_w=304;
9217 static int32_t box_h=176;
9218 static int32_t box_l=8;
9219 static int32_t box_r=312;
9220 static int32_t box_t=32;
9221 static int32_t box_b=208;
9222 static bool box_log=true;
9223 static char box_log_msg[480];
9224 static int32_t box_msg_pos=0;
9225 static int32_t box_store_pos=0;
9226
9227 int32_t onSnapshot2()
9228 {
9229 char buf[20];
9230 int32_t num=0;
9231
9232 do
9233 {
9234 sprintf(buf, "zelda%03d.bmp", ++num);
9235 }
9236 while(num<999 && exists(buf));
9237
9238 PALETTE temppal;
9239 get_palette(temppal);
9240 BITMAP *tempbmp=create_bitmap_ex(8,screen->w, screen->h);
9241 blit(screen,tempbmp,0,0,0,0,screen->w,screen->h);
9242 save_bitmap(buf,screen,temppal);
9243 destroy_bitmap(tempbmp);
9244 return D_O_K;
9245 }
9246
9247 void set_default_box_size()
9248 {
9249 int32_t screen_w = screen->w;
9250 int32_t screen_h = screen->h;
9251
9252 box_w=MIN(512, screen_w-16);
9253 box_h=MIN(256, (screen_h-64)&0xFFF0);
9254
9255 box_l=(screen_w-box_w)/2;
9256 box_t=(screen_h-box_h)/2;
9257 box_r=box_l+box_w;
9258 box_b=box_t+box_h;
9259 }
9260 /* resizes the box */
9261 void set_box_size(int32_t w, int32_t h)
9262 {
9263 int32_t screen_w = zq_screen_w;
9264 int32_t screen_h = zq_screen_h;
9265
9266 if(w <= 0) w = 512;
9267 if(h <= 0) h = 256;
9268 box_w=MIN(w, screen_w-16);
9269 box_h=MIN(h, (screen_h-64)&0xFFF0);
9270
9271 box_l=(screen_w-box_w)/2;
9272 box_t=(screen_h-box_h)/2;
9273 box_r=box_l+box_w;
9274 box_b=box_t+box_h;
9275 }
9276
9277 /* starts outputting a progress message */
9278 7 void box_start(int32_t style, const char *title, FONT *title_font, FONT *message_font, bool log, int32_t w, int32_t h, uint8_t scale)
9279 {
9280
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (is_headless())
9281 7 return;
9282
9283 box_text_scale=scale;
9284 box_style=style;
9285 box_title_font=(title_font!=NULL)?title_font:font;
9286 box_message_font=(message_font!=NULL)?message_font:font;
9287 box_message_height=text_height(box_message_font)*scale;
9288 box_titlebar_height=title?text_height(box_title_font)+2:0;
9289 set_box_size(w,h);
9290 /*
9291 box_w=BOX_W;
9292 box_h=BOX_H;
9293 box_l=BOX_L;
9294 box_r=BOX_R;
9295 box_t=BOX_T;
9296 box_b=BOX_B;
9297 */
9298 box_log=log;
9299 memset(box_log_msg, 0, 480);
9300 box_msg_pos=0;
9301 box_store_pos=0;
9302
9303 if(!box_active)
9304 popup_zqdialog_start();
9305 jwin_draw_win(screen, box_l, box_t, box_r-box_l, box_b-box_t, FR_WIN);
9306
9307 if(title!=NULL)
9308 {
9309 zc_swap(font,box_title_font);
9310 jwin_draw_titlebar(screen, box_l+3, box_t+3, box_r-box_l-6, 18, title, false);
9311 zc_swap(font,box_title_font);
9312 box_titlebar_height=18;
9313 }
9314
9315
9316 box_store_x = box_x = box_y = 0;
9317 box_active = true;
9318 box_t+=box_titlebar_height;
9319 box_h-=box_titlebar_height;
9320 box_log=log;
9321 memset(box_log_msg, 0, 480);
9322 box_msg_pos=0;
9323 box_store_pos=0;
9324 7 }
9325
9326 /* outputs text to the progress message */
9327 36784 void box_out(const char *msg)
9328 {
9329
1/2
✓ Branch 0 taken 36784 times.
✗ Branch 1 not taken.
36784 string remainder = "";
9330
1/2
✓ Branch 0 taken 36784 times.
✗ Branch 1 not taken.
36784 string temp(msg);
9331
9332
1/2
✓ Branch 0 taken 36784 times.
✗ Branch 1 not taken.
36784 if(box_active)
9333 {
9334 //do primitive text wrapping
9335 uint32_t i;
9336 for(i=0; i<temp.size(); i++)
9337 {
9338 int32_t length = text_length(box_message_font,temp.substr(0,i).c_str())*box_text_scale;
9339
9340 if(length > box_r-box_l-16)
9341 {
9342 i = zc_max(i-1,0);
9343 break;
9344 }
9345 }
9346
9347 set_clip_rect(screen, box_l+8, box_t+1, box_r-8, box_b-1);
9348 if(box_text_scale == 1)
9349 textout_ex(screen, box_message_font, temp.substr(0,i).c_str(), box_l+8+box_x, box_t+(box_y+1)*box_message_height, gui_fg_color, gui_bg_color);
9350 else
9351 {
9352 int32_t length = text_length(box_message_font,temp.substr(0,i).c_str());
9353 BITMAP* tempbit = create_bitmap_ex(8, length, box_message_height);
9354 clear_bitmap(tempbit);
9355 textout_ex(tempbit, box_message_font, temp.substr(0,i).c_str(), 0, 0, gui_fg_color, gui_bg_color);
9356 stretch_blit(tempbit, screen, 0, 0, length, box_message_height/box_text_scale, box_l+8+box_x, box_t+(box_y+1)*box_message_height, length*box_text_scale, box_message_height);
9357 destroy_bitmap(tempbit);
9358 }
9359 set_clip_rect(screen, 0, 0, screen->w-1, screen->h-1);
9360 remainder = temp.substr(i,temp.size()-i);
9361 }
9362
9363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36784 times.
36784 if(box_log)
9364 {
9365 36784 sprintf(box_log_msg+box_msg_pos, "%s", msg);
9366 36784 }
9367
9368
1/2
✓ Branch 0 taken 36784 times.
✗ Branch 1 not taken.
36784 box_x += text_length(box_message_font, msg);
9369 36784 box_msg_pos+=(int32_t)strlen(msg);
9370
9371
2/4
✓ Branch 0 taken 36784 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36784 times.
36784 if(remainder != "")
9372 {
9373 bool oldlog = box_log;
9374 box_log = false;
9375 box_eol();
9376 box_out(remainder.c_str());
9377 box_log = oldlog;
9378 }
9379
9380 // For web, always call update_hw_screen because it yields to the main thread,
9381 // which makes long running tasks like loading a quest not block the main thread,
9382 // which would make SFX sound awful on the title screen.
9383
3/6
✓ Branch 0 taken 36784 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36784 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 36784 times.
36784 if (box_active || is_web())
9384 update_hw_screen();
9385 36784 }
9386
9387 /* calls box_out, and box_eol for newlines */
9388 void box_out_nl(const char *msg)
9389 {
9390 string line;
9391 istringstream reader(msg);
9392 while (getline(reader, line))
9393 {
9394 box_out(line.c_str());
9395 box_eol();
9396 }
9397 }
9398
9399 /* remembers the current x position */
9400 160 void box_save_x()
9401 {
9402
1/2
✓ Branch 0 taken 160 times.
✗ Branch 1 not taken.
160 if(box_active)
9403 {
9404 box_store_x=box_x;
9405 }
9406
9407 160 box_store_pos=box_msg_pos;
9408 160 }
9409
9410 /* remembers the current x position */
9411 156 void box_load_x()
9412 {
9413
1/2
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
156 if(box_active)
9414 {
9415 box_x=box_store_x;
9416 }
9417
9418 156 box_msg_pos=box_store_pos;
9419 156 }
9420
9421 /* outputs text to the progress message */
9422 18619 void box_eol()
9423 {
9424
1/2
✓ Branch 0 taken 18619 times.
✗ Branch 1 not taken.
18619 if(box_active)
9425 {
9426 box_x = 0;
9427 box_y++;
9428
9429 if((box_y+2)*box_message_height >= box_h)
9430 {
9431 blit(screen, screen, box_l+8, box_t+(box_message_height*2), box_l+8, box_t+(box_message_height), box_w-16, box_y*box_message_height);
9432 rectfill(screen, box_l+8, box_t+box_y*box_message_height, box_l+box_w-8, box_t+(box_y+1)*box_message_height, gui_bg_color);
9433 box_y--;
9434 }
9435 }
9436
9437 18619 box_msg_pos = 0;
9438
9439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18619 times.
18619 if(box_log)
9440 {
9441 18619 al_trace("%s", box_log_msg);
9442 18619 al_trace("\n");
9443 18619 memset(box_log_msg, 0, 480);
9444 18619 }
9445
9446
1/2
✓ Branch 0 taken 18619 times.
✗ Branch 1 not taken.
18619 if (box_active)
9447 update_hw_screen();
9448 18619 }
9449
9450 /* ends output of a progress message */
9451 702 void box_end(bool pause)
9452 {
9453
1/2
✓ Branch 0 taken 702 times.
✗ Branch 1 not taken.
702 if(box_active)
9454 {
9455 if(pause)
9456 {
9457 box_eol();
9458 box_pause();
9459 }
9460
9461 box_active = false;
9462 popup_zqdialog_end();
9463 }
9464 702 }
9465
9466 /* pauses box output */
9467 void box_pause()
9468 {
9469 if(box_active)
9470 {
9471 box_save_x();
9472 box_out("-- press a key --");
9473
9474 while(gui_mouse_b()) rest(1);
9475 while(!(keypressed() || gui_mouse_b())) rest(1);
9476 while(gui_mouse_b()) rest(1);
9477
9478 clear_keybuf();
9479 box_load_x();
9480 }
9481 }
9482